定义lambda表达式时使用泛型类型参数<T>

3VY*_*z7t 2 java java-8 java-stream

请考虑以下代码段:

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

}
Run Code Online (Sandbox Code Playgroud)

有没有办法解决lambdaConcat这两个相应的陈述main()变得正确?

我想表达的类型BinaryOperator<List<Number>>,BinaryOperator<List<?>>,BinaryOperator<List<? extends Number>>,甚至BinaryOperator<List>,但是,可以理解的,他们没有工作.理想情况下,我想编写lambdaConcat一个类型参数<T>和我一样的functionConcat,但我还没有找到一种方式来表达与lambda表达式.

Luk*_*der 5

这不起作用,因为reduce()操作BinaryOperator<T>是不变的:

T reduce(T identity, BinaryOperator<T> accumulator);
Run Code Online (Sandbox Code Playgroud)

这实际上意味着如果您传递一个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());
}
Run Code Online (Sandbox Code Playgroud)

你现在可以写:

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());
Run Code Online (Sandbox Code Playgroud)

当然,在这一点上,方法参考解决方案可能仍然更好.