Generics and streams: how to do this in `StreamTuple :: new`?

I am working on a small library that emulates the values ​​of the values ​​returned by multiple values ​​in streams. For this to work well, I would like to use StreamTuple::newinstead of StreamTuple::createor id -> new StreamTuple<>(id, id). I tried various modifications, but my generics-fu are not good enough to understand how to change the source to allow this.

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);
    }
    ....

Call code snippet:

    Map<String, String> m = Stream.of("1", "2", "3")
//          .map(StreamTuple::create)
            .map(id -> new StreamTuple<>(id, id))
            .collect(toMap(StreamTuple::left, StreamTuple::right));

Suggestions? Or can not be done?


EDIT: , StreamTuple, L R . , , , . , L/R, - . ?

+4
5

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);
    }        
}
+2

, id . StreamTuple::create - .

+1

Stream map method Function, - .

, , StreamTuple::new, 2 , . a BiFunction, .

, flatMap , , Collector 2 , , create, .

- , - factory, StreamTuple.

+1

StramTuple::new - FunctionalInterface, .

Function (T → R) == > :: new new StreamTuple(t)

BiFunction (T, U → R) == > :: new new StreamTuple(t,u)

Supplier (() → R) == > :: new new StreamTuple()

Stream # Function, 2-args. , create factory .

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 , :

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; }
}
+1
source

There is no way to do this with the constructor, because there is no way to indicate that the argument is a subtype of both L, and R(i.e., join / intersection). The language has a construction for this requirement, but intersection between type variables is not allowed:

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

This may work in a future version of Java.

You should use the factory method or, I suppose, what tsolakp suggested. I think factory makes more sense.

+1
source

Source: https://habr.com/ru/post/1693601/


All Articles