泛型和流:如何将它变成`StreamTuple :: new`语句?

时间:2018-02-13 21:19:29

标签: java generics

我正在开发一个小型库,它在Streams中模拟多值返回值。为了使其运作良好,我希望能够使用import UIKit class URLRequestGroup { var dispatchGroup: DispatchGroup init(dispatchGroup: DispatchGroup) { self.dispatchGroup = dispatchGroup } init() { self.dispatchGroup = DispatchGroup() } func beginURLRequest(urlRequest: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> ()) { let urlSession = URLSession(configuration: URLSessionConfiguration.default) // Enter the dispatchGroup manually dispatchGroup.enter() urlSession.dataTask(with: urlRequest, completionHandler: { [weak self] data, urlResponse, error in completionHandler(data, urlResponse, error) // Leave this dispatchGroup. self?.dispatchGroup.leave() }).resume() } } let group = URLRequestGroup() group.beginURLRequest(urlRequest: URLRequest(url: URL(fileURLWithPath: "http://www.example.com")), completionHandler: { data, urlResponse, error in print(data?.count ?? 0) }) // Put any other request here. group.dispatchGroup.wait() 代替StreamTuple::newStreamTuple::create。我尝试了各种修改,但是我的generics-fu不足以弄清楚如何更改源代码来实现这一点。

id -> new StreamTuple<>(id, id)

调用代码段:

public class StreamTuple<L, R> {

    protected final L left;
    protected final R right;

    public StreamTuple(L left, R right) {
        this.left = left;
        this.right = right;
    }

    /**
     * Suitable for method::references.  Value is set to id.
     */

    public static <L> StreamTuple<L, L> create(L left) {
        return new StreamTuple<>(left, left);
    }
    ....

连连呢?或者不能这样做?

编辑:我想要一个额外的构造函数,它只接受一个参数并返回一个StreamTuple,其中L和R是相同的类型。目前的代码并没有反映出这一点,因为它不久之前我无法使它工作,我想我复制了它。我只能找到如何提供一个L / R并让另一个开放。如何为此编写单个参数构造函数?

5 个答案:

答案 0 :(得分:2)

您是否考虑过扩展StreamTuple以定义单个参数构造函数?

 Map<String, String> m = Stream.of("1", "2", "3")
.map( UnaryStreamTuple<String>::new )
.collect( Collectors.toMap(UnaryStreamTuple::left, UnaryStreamTuple::right) );

public class UnaryStreamTuple<T> extends StreamTuple<T, T> {

    public UnaryStreamTuple(T left) {
        super(left, left);
    }

    public UnaryStreamTuple(T left, T right) {
        super(left, right);
    }        
}

答案 1 :(得分:1)

由于您传递id两次,因此无法完成。 StreamTuple::create是要走的路。

答案 2 :(得分:1)

Stream https://issues.apache.org/jira/browse/FLINK-8485需要一个Function,它只接受一个参数并返回其他内容。

但是,您尝试使用的是StreamTuple::new,并且它包含2个参数,例如BiFunction,因此不匹配。

我想你可以使用flatMap来获得每个流元素的两个副本,然后map method一次收集这些项目2,但这听起来比引用你的{{{{{{ 1}}方法,已匹配。

最有效的是你所做的 - 一种工厂方法只需一个参数并返回所需的create

答案 3 :(得分:1)

StramTuple::new将根据接受方法所期望的FunctionalInterface进行不同的翻译。

期待Function(T - > R)==&gt; :: new转换为new StreamTuple(t)

期待BiFunction(T,U - > R)==&gt; :: new转换为new StreamTuple(t,u)

期待Supplier(() - &gt; R)==&gt; :: new转换为new StreamTuple()

由于Stream#map需要Function,因此无法转换为2-args构造函数。所以你的create工厂方法似乎是一个很好的方法。

有一个1-arg构造函数(如下所示)的行为类似于create方法是不可能的,因为编译器会抱怨因为R没有绑定

public StreamTuple(L both) { //will fail compilation
    this.left = both;
    this.right = both;
}

但是,因为你想要一个1-arg构造函数,并且它的参数必须可以分配给R和L,那么你有2个选项: 1)一个扩展另一个(例如R可分配给L)

public class StreamTuple<L, R extends L> {

    protected final L left;
    protected final R right;

    public StreamTuple(R both) {
        this.left = both;
        this.right = both;
    }
}

2)如果R和L不相关,那么你需要在getter上使用强制转换的对象:

public class StreamTuple<L, R> {

    protected final Object left, right;

    public StreamTuple(Object o) {
        this.left = this.right = o;
    }

    public <L> L getLeft() { return (L) left; }
    public <R> R getRight() { return (R) right; }
}

答案 4 :(得分:1)

使用构造函数无法做到这一点,因为没有办法指定参数是LR的子类型(即连接/交集)。该语言具有这种要求的构造,但不允许类型变量之间的交集:

// not allowed (causes a compilation error)
//                 vvvvv
public <LR extends L & R> StreamTuple(LR val) {
    this.left = val;
    this.right = val;
}

然而,这可能适用于Java的未来版本。

你必须使用工厂方法,或者我想,tsolakp建议使用什么。我认为工厂更有意义。