2016-08-18 8 views
2

を定義し、次のスニペットを考えてみましょう:利用ラムダ式

public class JavaApplication4 { 

    static <T> List<T> functionConcat(List<T> l1, List<T> l2) { 
     return Stream.concat(l1.stream(), l2.stream()).collect(Collectors.toList()); 
    } 

    // functionConcat in lambda form 
    static final BinaryOperator<List<? extends Number>> lambdaConcat = (l1, l2) 
      -> Stream.concat(l1.stream(), l2.stream()).collect(Collectors.toList()); 

    public static void main(String[] args) { 
     // DOES NOT WORK with lambdaConcat 
     final List<Integer> x = new LinkedList<List<Integer>>() 
       .stream().reduce(new LinkedList<>(), lambdaConcat); 
     final List<Double> y = new LinkedList<List<Double>>() 
       .stream().reduce(new LinkedList<>(), lambdaConcat); 

     // WORKS with functionConcat 
     final List<Integer> x2 = new LinkedList<List<Integer>>() 
       .stream().reduce(new LinkedList<>(), JavaApplication4::functionConcat); 
     final List<Double> y2 = new LinkedList<List<Double>>() 
       .stream().reduce(new LinkedList<>(), JavaApplication4::functionConcat); 
    } 

} 

lambdaConcatmain()で対応する二つの文が正しいとなっていることを解決する方法はありますか?

私はBinaryOperator<List<Number>>BinaryOperator<List<?>>BinaryOperator<List<? extends Number>>、とさえBinaryOperator<List>ようなタイプを表現しようとしたが、、当然のことながら、それらのどれも動作しません。理想的には、私は私がfunctionConcatで行ったように型パラメータ<T>lambdaConcatを書きたいと思いますが、私はラムダ式でそれを表現する方法を発見していません。

答えて

5

reduce()操作のBinaryOperator<T>不変であるので、これは動作しません:

T reduce(T identity, BinaryOperator<T> accumulator); 

これは、本質的に、あなたがアイデンティティとしてList<Integer>型を渡す場合、あなたはまた、アキュムレータとしてBinaryOperator<List<Integer>>を渡すために持っていることを意味し、ではありませんa BinaryOperator<List<? extends Number>>

<T>が毎回List<Integer>に正しく推論されるため、メソッド参照を使用する場合やラムダ式を2回インライン展開する場合は、この問題に遭遇することはありません。問題は、固定式にあなたのラムダを割り当てることにより、型推論のこの種のを防ぐことです。もし、代わりに、あなたがラムダを返さ高次汎用関数を書いて、それが再び動作します:

static final <T extends Number> BinaryOperator<List<T>> lambdaConcat() { 
    return (l1, l2)->Stream.concat(l1.stream(), l2.stream()).collect(Collectors.toList()); 
} 

あなたは今書くことができます。もちろん

final List<Integer> x = new LinkedList<List<Integer>>() 
     .stream().reduce(new LinkedList<>(), lambdaConcat()); 
final List<Double> y = new LinkedList<List<Double>>() 
     .stream().reduce(new LinkedList<>(), lambdaConcat()); 

を、この時点では、メソッド参照を解決策はおそらくまだ良いです。

+1

は、あなたの究極の結論に反対するまでもありませんが、 'BinaryOperator は 'T'は、入力と出力の両方に使用されているので、'不変である必要があります。そして、出力のために、 '? Numberは十分に正確ではない。私たちは、あなたが示してきたように 'T'が 'Integer'または' Double'する必要があります。オリジナルの 'lambdaConcat'はランク2多型の試みであると思われることに注意してください!実際 –

+1

@JohnVasileff、: 'BinaryOperator'は不変である必要があります –