2017-10-21 134 views
1

我需要一个番石榴MultiSet.Entry的比较器,按count计数和String second排序。但是,我遇到了编译器问题,我想我对泛型有所错误。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); 
} 

我在这里错过了什么,以及如何才能使它工作?

(注:我知道有可能是与番石榴不同的方法,但我想知道我来到这里的问题。)

+1

我没有声称明白为什么它是必要的,但你可以通过为第一个方法调用添加显式类型参数来获得这些'thenComparing'链。比较器,Integer>比较(Multiset.Entry :: getCount).thenComparing(Multiset.Entry :: getElement);' –

+3

您还应该使用comparatorInt()进行第一次比较:'return Comparator。< Multiset.Entry > ComparisonInt(Multiset.Entry :: getCount).thenComparing(Multiset.Entry :: getElement);' –

+0

comparatorInt()是有意义的,但它仍然需要显式类型参数。为什么需要使用MultiSet.Entry,但不使用String? –

回答

2

认为这是因为如何定位类型(Java的形式推理)与代码中使用的点函数编程一起工作(您可以阅读java文档中的目标类型here,特别是名为Target Types and Method Arguments的部分)。

在很短的,如果我有这样的事情:

List<String> list = new List<>(); 

这里的目标类型是List<String>所以Java(8)认识到要创建新的列表被分配到,应该是类型List<String>,因此可以推断出类型,并且不必指定类型参数。

它归结为,做编译第一snippest是:代码Comparator.comparing(Multiset.Entry::getCount);的部分返回一个类型的Comparator<T>,这一结果立即分配给方法的返回类型(即方法的返回类型是目标类型)。编译器可以推断出类型,因为目标类型是方法comparator的返回类型,您在方法签名中明确定义/捕获的方法为Comparator<Multiset.Entry<String>>。因此可以推断出Comparator<T>中的T

在代码的第二部分(不编译并要求显式类型见证变量 - 方法调用的<>中的显式位),您正在使用链式方法的点运算符。这意味着第二部分thenComparing(Multiset.Entry::getElement)适用于第一部分Comparator.comparing(Multiset.Entry::getCount)的结果。

第二部分可以从目标类型推断出类型,因为第二部分的结果是该方法返回的结果,所以第二部分的目标类型与上面编译过的情况类似 - 方法返回类型被捕获和定义,因此它可以推断出这一点。

但是对于第一部分来说,目标类型是不确定的,因为它没有被分配给具有实际类型的某种类型。根据比较器API,Comparator<T>是该函数返回的内容,但由于它不知道具体将分配哪种类型,因此需要提供类型见证并明确指定当它返回Comparator<T>T应该(在你的情况下)Multiset.Entry<String>

+0

P.s.我对番石榴的了解不多 - 因此不确定番石榴是否对推理工作有影响。 – Smiley

+0

啊,我显然没有意识到与lambda类型相关的类型推断的所有含义。感谢您的详细解答,我相信它与番石榴无关。 –

+0

鉴于“实际和正式参数列表长度不同”的消息,这是不对的。至少,我不明白错误大小的参数列表来自哪里。 – maaartinus