我需要一个guava MultiSet.Entry的比较器,用于按计数排序和字符串秒排序。但是,我遇到编译器问题,我认为我得到了泛型错误的东西。
编译:
Comparator<Multiset.Entry<String>> comparator() {
return Comparator.comparing(Multiset.Entry::getCount);
}
然而,这不是:
Comparator<Multiset.Entry<String>> comparator() {
return Comparator.comparing(Multiset.Entry::getCount).thenComparing(Multiset.Entry::getElement);
}
Error: java: incompatible types: cannot infer type-variable(s) T,U (argument mismatch; invalid method reference method getCount in interface com.google.common.collect.Multiset.Entry cannot be applied to given types required: no arguments found: java.lang.Object reason: actual and formal argument lists differ in length)
如果我将比较器组合在一起,例如对于一个字符串,我显然没有类似的问题。
Comparator<String> comparator2() {
return Comparator.comparing(String::length).thenComparing(String::toString);
}
我在这里缺少什么,我怎样才能让它发挥作用?
(注意:我知道Guava可能有不同的方法,但我想了解我在这里遇到的问题。)
答案 0 :(得分:2)
我认为是因为类型定位(一种Java推理形式)与代码中使用的点功能编程一起工作(您可以阅读有关目标类型here的内容java文档,特别是名为Target Types and Method Arguments
)的部分。
非常简短,如果我有这样的话:
List<String> list = new List<>();
此处的目标类型为List<String>
,因此Java(8)意识到您正在创建的新列表已分配给List<String>
类型,因此可以推断出类型,并且您可以不必指定类型参数。
编译的第一个代码是:代码Comparator.comparing(Multiset.Entry::getCount);
的部分返回Comparator<T>
的类型,此结果立即分配给方法的返回类型(即方法的返回类型是目标类型)。编译器可以推断类型,因为目标类型是方法comparator
的返回类型,您在方法签名中明确定义/捕获为Comparator<Multiset.Entry<String>>
。因此可以推断出T
中的Comparator<T>
。
在第二段代码中(不编译并需要显式类型见证参数 - 方法调用的&lt;&gt;中的显式位),您使用的是连接方法的点运算符。这意味着第二部分thenComparing(Multiset.Entry::getElement)
将应用于第一部分Comparator.comparing(Multiset.Entry::getCount)
的结果。
第二部分可以从目标类型推断出类型,因为第二部分的结果是方法返回的结果,所以第二部分的目标类型类似于上面编译的情况 - 方法返回类型被捕获并定义,因此它可以推断出这一点。
但是对于第一部分,目标类型是不确定的,因为它没有被分配给具有实际类型的某种类型。根据Comparator API,Comparator<T>
是该函数返回的内容,但由于它不知道它将特定分配给哪种类型,因此您需要提供类型见证并明确指定它何时返回Comparator<T>
T
应该是(在您的情况下)Multiset.Entry<String>
。