无法在意外地方推断类型(可能是Javac错误?)

我正在尝试执行新的JDK 8函数式编程领域中似乎是相对基本的事情,但是我无法使其工作。我有这个工作代码:

import java.util.*;

import java.util.concurrent.*;

import java.util.stream.*;

public class so1 {

public static void main() {

List<Number> l = new ArrayList<>(Arrays.asList(1, 2, 3));

List<Callable<Object>> checks = l.stream().

map(n -> (Callable<Object>) () -> {

System.out.println(n);

return null;

}).

collect(Collectors.toList());

}

}

它接受一个数字列表,并产生可以打印出来的功能列表。但是,显式转换为Callable似乎是多余的。在我和IntelliJ中看来。我们都同意这也应该起作用:

List<Callable<Object>> checks = l.stream().

map(n -> () -> {

System.out.println(n);

return null;

}).

collect(Collectors.toList());

但是我得到一个错误:

so1.java:10: error: incompatible types: cannot infer type-variable(s) R

List<Callable<Object>> checks = l.stream().map(n -> () -> {System.out.println(n); return null;}).collect(Collectors.toList());

^

(argument mismatch; bad return type in lambda expression

Object is not a functional interface)

where R,T are type-variables:

R extends Object declared in method <R>map(Function<? super T,? extends R>)

T extends Object declared in interface Stream

1 error

回答:

您遇到了Java 8目标类型的限制,该限制适用于方法调用的 接收者 。尽管目标类型在大多数情况下适用于参数类型,但不适用于调用该方法的对象或表达式。

这里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());

这不会降低代码的复杂性,但可以毫无问题地进行编译。对我来说,这是déjàvu。当Java

5和泛型问世时,程序员必须在new表达式上重复类型参数,而只是将表达式包装到泛型方法中就证明了推断类型是没有问题的。直到Java

7才允许程序员忽略类型参数的这些不必要的重复(使用“菱形运算符”)。现在,我们遇到了类似的情况,将调用表达式包装到另一种方法中,将接收者变成参数,证明此限制是不必要的。所以也许我们摆脱了Java

10中的这个限制…

以上是 无法在意外地方推断类型(可能是Javac错误?) 的全部内容, 来源链接: utcz.com/qa/402098.html

回到顶部