Comparator.comparing(...)在使用String :: compareTo时抛出非静态引用异常

时间:2017-04-07 09:16:32

标签: java java-8 static-methods comparator method-reference

以下是我的代码段的两行:

List<String> listDevs = Arrays.asList("alvin", "Alchemist", "brutus", "larsen", "jason", "Kevin");

listDevs.sort(Comparator.comparing(String::length)); //This works fine
listDevs.sort(String::compareToIgnoreCase); //This works fine

但是(在expermient之外)当我尝试写

listDevs.sort(Comparator.comparing(String::compareToIgnoreCase));

编译器抛出错误

  

无法对非静态方法进行静态引用   来自String

类型的compareToIgnoreCase(String)

类似的情况发生在下面的代码

listDevs.sort(Comparator.comparing(String::compareTo));

我理解错误,如果我删除Comparator.comparing(如上所示),它可以正常工作。

但我的观点是,这条线如何运作?

  

listDevs.sort(Comparator.comparing(字符串::长度));

我相信我错过了一些东西。我看过this帖子。这是同样的情况吗?

3 个答案:

答案 0 :(得分:13)

Comparator.comparing需要一个Function来描述元素的可比属性。所以String::length就足够了length()String评估Stringint的属性(这就是为什么comparingInt更可取的原因)

相比之下,String.compareToIgnoreCaseString.compareTo比较方法。他们比较了两个String个对象。因此,在预期Comparator的情况下,对它们的引用就足够了,而不是预期属性Function的位置。

就像你有一家工厂说“Gimme是一个发动机,我们为你制造一辆汽车”,你正试图给他们一辆完整的汽车。虽然现有的汽车在预计有车的情况下是有效的,但将其运到工厂制造汽车是没有意义的。

不幸的是,当前的编译器实现在报告功能签名错误方面非常糟糕。当签名不匹配时,您几乎总会看到诸如“无法对非静态方法进行静态引用...”之类的消息。

答案 1 :(得分:5)

sort方法需要Comparator

当你这样做时,你确实提供了一个。

 listDevs.sort(Comparator.comparing(String::length));

这里也是如此(但有点不直观):

 listDevs.sort(String::compareToIgnoreCase)
 listDevs.sort((left, right) -> left.compareToIgnoreCase(right)); // same thing as above

这正是Comparator的定义 - 取两个字符串并返回一个int。

你说它是如何工作的:listDevs.sort(Comparator.comparing(String::length));实际上非常简单。

Comparator.comparing需要Function将您的输入类型转换为Comparable。在您的情况下,需要String并返回Integer;这是可比的。

答案 2 :(得分:4)

JLS ReferenceType :: [TypeArguments]标识符的方法参考编译时声明可以用不同的方式解释。

  

给定具有n个参数的目标函数类型,确定了一组可能适用的方法:

     

ReferenceType :: [TypeArguments]标识符有两个不同的元素,n和n-1,用于考虑此表单引用静态方法或实例方法的可能性。

     

可以用不同的方式解释ReferenceType :: [TypeArguments]标识符形式的方法引用表达式。如果Identifier引用实例方法,则隐式lambda表达式具有类型为 this 的额外参数,与标识符引用静态方法相比。 ReferenceType可能有两种适用的方法,因此上面描述的搜索算法会单独识别它们,因为每种情况都有不同的参数类型。

Comparator.comparing方法接受Function<T,R extends Comparable<? super R>>。当你使用会报告错误的String::compareToIgnoreCase时,因为它有两个参数,一个隐含这个另一个是比较字符串的方法参数,所以更像是BiFunction<String,String,Integer>而不是Function<String,Integer>

BiFunction<String, String, Integer> comparator = String::compareToIgnoreCase;
// you can't assign a BiFunction to a Function
// because one is incompatiable with another.
Function<String,Integer> function = comparator;

Stream.sort方法接受Comparator,而比较器更像BiFunction<T,T,Integer>,因此它与String::compareToIgnoreCase兼容。另一方面,它们可以互换。例如:

Comparator<String> primary = String::compareToIgnoreCase;
BiFunction<String, String, Integer> comparator1 = primary::compare;
Comparator<String> comparator2 = comparator1::apply;

您可以改为使用comparing(String::toLowerCase),它与String::compareToIgnoreCase同等,例如:

// String::compareToIgnoreCase
listDevs.sort(String::compareToIgnoreCase); 

// comparing(String::toLowerCase)
listDevs.sort(comparing(String::toLowerCase))