Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/350.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Java在对lambda使用泛型时选择对象参数化类型?_Java_Generics_Lambda_Java 8 - Fatal编程技术网

为什么Java在对lambda使用泛型时选择对象参数化类型?

为什么Java在对lambda使用泛型时选择对象参数化类型?,java,generics,lambda,java-8,Java,Generics,Lambda,Java 8,假设我有一个方法,它接受java.util.function.Predicate并返回CompletableFuture: public <R> CompletableFuture<R> call(Predicate<R> request) { return new CompletableFuture<>(); } 它不会编译,因为Java认为它是一个谓词,并返回如下消息: Integer a = call(new Predicate&l

假设我有一个方法,它接受java.util.function.Predicate并返回CompletableFuture:

public <R> CompletableFuture<R> call(Predicate<R> request) {
    return new CompletableFuture<>();
}
它不会编译,因为Java认为它是一个
谓词
,并返回如下消息:

Integer a = call(new Predicate<Integer>() {
    @Override
    public boolean test(Integer o) {
        return false;
    }
}).join();
Integer a = call(o -> false).join();
Error:(126, 42) java: incompatible types: java.lang.Object cannot be converted to java.lang.Integer
public <R> CompletableFuture<R> call(Predicate<? super R> request)
我发现了一些变通办法。我可以显式地创建
CompletableFuture
变量,而不是链接,或者添加一个不必要的额外参数
Class
,告诉Java我们要获取哪种类型,或者强制lambda表达式中的类型


然而,我想知道为什么Java在第一个lambda示例中选择了
Object
而不是
Integer
,因为它已经知道我想要哪种类型,所以编译器可以使用最具体的类型而不是
Object
,因为这三种解决方法对我来说都很难看。

Java 8的类型推断有限制,而且它不会查看您将结果分配给的变量的类型。相反,它为类型参数推断类型
对象

您可以通过在lambda中显式指定参数
o
的类型来修复它:

Integer a = call((Integer o) -> false).join();

其他人已经回答了如何强制lambda为正确的类型。然而,我认为,
谓词
对于该谓词并没有“错误”,应该允许您使用它——您对所有对象都有一个谓词——它应该对所有对象起作用,包括
整数
s;为什么需要对
Integer
s做更严格的谓词?你不应该

我认为真正的问题是
调用
方法的签名。太严格了
谓词
是其类型参数的使用者(它只有一个采用其类型参数类型并返回
布尔值的方法)
;因此,根据PECS规则(生产者
扩展
,消费者
超级
),您应该始终将其与
超级
有界通配符一起使用

因此,您应该这样声明您的方法:

Integer a = call(new Predicate<Integer>() {
    @Override
    public boolean test(Integer o) {
        return false;
    }
}).join();
Integer a = call(o -> false).join();
Error:(126, 42) java: incompatible types: java.lang.Object cannot be converted to java.lang.Integer
public <R> CompletableFuture<R> call(Predicate<? super R> request)

<代码>公共完全未来调用(PredicateYes),这是我建议的一个解决方案,但我认为它也很难看,因为如果在lambda表达式中有多个参数,我必须声明所有参数的类型。(RingMap服务,OperationContext ctx1)->ctx1.reply(service.getRing()).join();@burakemre没有免费的午餐。类型推断需要一些类型信息来处理。它非常擅长从大多数程序中查找一些类型信息,但如果您不提供任何可处理的信息,它就无法发挥作用。添加额外的类型信息不是一种“变通方法”;它为类型推断提供了足够的信息来解决您要求它解决的问题。偶尔在lambda参数上添加清单类型实际上并没有那么麻烦。您还可以在call方法上添加显式类型见证:
receiver.call(…)
在干扰性较小的情况下。@BrianGoetz我真的不明白为什么很难找到给定场景的类型推断。If CompletableFuture.join()返回参数化类型,如果该类型是从其他地方推断出来的,我假设Java可以通过查看如何使用调用(谓词)返回的变量来理解这被认为是一个弱点,而AFAIK Scala并没有遇到这个问题。然而,我只是语言语义领域的初学者,所以如果你知道关于它的任何文章,如果你能分享一下,那就太好了。@Burak emre参见D节。Java 8显著增强了Java 8类型推断,但不足以进行链式表达式推断ike this.“人们对允许推理“链”产生了一些兴趣:在a().b()中,将类型信息从b的调用传递到a的调用。这增加了推理算法的复杂性的另一个维度,因为部分信息必须双向传递;它只在删除a()的返回类型时起作用。”对于所有实例化(例如列表)都是固定的。由于目标类型无法轻松派生,因此此功能不太适合于多边形表达式模型;但可能通过其他增强功能,可以在将来添加它。”请参见此处: