您遇到了 Java 8 目标类型的限制,该限制适用于receiver的方法调用。虽然目标类型适用于参数类型(大多数情况下),但它不适用于您调用方法的对象或表达式。
Here, l.stream().
map(n -> () -> {
System.out.println(n);
return null;
})
是接收者collect(Collectors.toList())
方法调用,所以目标类型List<Callable<Object>>
不考虑它。
如果目标类型已知,则很容易证明嵌套 lambda 表达式可以工作,例如
static <T> Function<T,Callable<Object>> toCallable() {
return n -> () -> {
System.out.println(n);
return null;
};
}
工作没有问题,你可以用它来解决你原来的问题
List<Callable<Object>> checks = l.stream()
.map(toCallable()).collect(Collectors.toList());
您还可以通过引入辅助方法来解决问题,该方法将第一个表达式的角色从方法接收者更改为参数
// turns the Stream s from receiver to a parameter
static <T, R, A> R collect(Stream<T> s, Collector<? super T, A, R> collector) {
return s.collect(collector);
}
并将原来的表达式改写为
List<Callable<Object>> checks = collect(l.stream().map(
n -> () -> {
System.out.println(n);
return null;
}), Collectors.toList());
这不会降低代码的复杂性,但可以毫无问题地编译。对我来说,这是一种似曾相识的感觉。当 Java 5 和泛型出现时,程序员必须重复使用类型参数new
表达式,同时简单地将表达式包装到泛型方法中,证明推断类型是没有问题的。直到 Java 7 才允许程序员省略这些不必要的类型参数重复(使用“菱形运算符”)。现在我们有类似的情况,将调用表达式包装到另一个方法中,将接收者变成参数,证明这种限制是不必要的。所以也许我们可以在 Java 10 中摆脱这个限制……