2016-08-18 118 views
2

時,要考慮下面的代碼片段:使用泛型類型參數<T>的定義lambda表達式

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

} 

有沒有辦法解決lambdaConcat使得main()兩個對應的語句變成正確的?

我試圖表達類型爲BinaryOperator<List<Number>>BinaryOperator<List<?>>BinaryOperator<List<? extends Number>>,甚至BinaryOperator<List>,但是,可以理解的,他們沒有工作。理想情況下,我想寫lambdaConcat,其類型參數<T>與我在functionConcat中所做的一樣,但我還沒有找到用lambda表達式表達的方法。

回答

5

這並不工作,因爲reduce()操作的BinaryOperator<T>是不變的:

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

這基本上意味着,如果你傳遞一個List<Integer>類型的身份,你也必須通過BinaryOperator<List<Integer>>由於儲液器,不一個BinaryOperator<List<? extends Number>>

使用方法引用時,或者在將lambda表達式內聯兩次時,您不會遇到此問題,因爲<T>可以每次正確推斷爲List<Integer>。問題是你通過將lambda分配給一個固定類型來阻止這種類型推斷。相反,如果你寫返回的拉姆達高階通用的功能,它會重新工作:

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'用於輸入和輸出。而且,對於輸出,'?擴展數字「不夠精確。如你所示,我們需要'T'爲'Integer'或'Double'。請注意,最初的'lambdaConcat'似乎是一個嘗試排名2多態性! –

+1

@JohnVasileff,確實:'BinaryOperator'必須是不變的 –

相關問題