请考虑以下代码段:
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表达式。< / p>
答案 0 :(得分: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分配给固定类型来阻止这种类型的推断。相反,如果您编写了一个返回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());
当然,在这一点上,方法参考解决方案可能仍然更好。