[英]Why Java chooses Object parameterized type when using generics with lambda?
假设我有一个采用java.util.function.Predicate并返回CompletableFuture的方法:
public <R> CompletableFuture<R> call(Predicate<R> request) {
return new CompletableFuture<>();
}
如果我使用这样的匿名类调用此方法:
Integer a = call(new Predicate<Integer>() {
@Override
public boolean test(Integer o) {
return false;
}
}).join();
它的工作原理是因为我必须明确声明谓词的类型。 但是,如果我使用lambda表达式而不是像这样的匿名类:
Integer a = call(o -> false).join();
它不会编译,因为Java认为它是Predicate<Object>
并返回如下消息:
Error:(126, 42) java: incompatible types: java.lang.Object cannot be converted to java.lang.Integer
我找到了一些解决方法。 我可能会显式创建CompletableFuture
变量而不是进行链接,或者添加不必要的额外参数Class<R>
来告诉Java我们要获取哪种类型或在lambda表达式中强制使用该类型。
但是我不知道为什么Java在第一个lambda示例中选择了Object
而不是Integer
,它已经知道我要获取哪种类型,因此编译器可以使用最特定的类型而不是Object
因为这三种解决方法对我来说都很难看。
Java 8的类型推断有一定的局限性,它不会查看将结果分配给的变量的类型。 相反,它推断出类型参数的类型Object
。
您可以通过在lambda中显式指定参数o
的类型来修复它:
Integer a = call((Integer o) -> false).join();
其他人已经回答了如何将lambda强制为正确的类型。 但是,我认为Predicate<Object>
对于该谓词并不“错误”,你应该被允许使用它 - 你有一个所有对象的谓词 - 它应该适用于所有对象,包括Integer
; 为什么需要对Integer
作出更严格的谓词? 你不应该。
我认为真正的问题是你的call
方法的签名。 这太严格了。 Predicate
是其类型参数的使用者 (它只有一个采用其类型参数类型并返回boolean
); 因此,根据PECS规则(“生产者extends
,“消费者super
),您应始终将其与super
界通配符一起使用。
因此,您应该这样声明您的方法:
public <R> CompletableFuture<R> call(Predicate<? super R> request)
无论您使用此方法使用什么代码,都将绑定更改为super
之后仍将编译,因为Predicate
是使用者。 现在,您无需强制将其设置为Predicate<Integer>
-您可以使用Predicate<Object>
并使它返回CompletableFuture<Integer>
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.