Java Comparator.comparing(…)在获取String::compareTo时引发非静态引用异常

Java Comparator.comparing(…)在获取String::compareTo时引发非静态引用异常,java,java-8,static-methods,comparator,method-reference,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 fi

下面是我的代码片段的两行:

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
编译器抛出错误

无法对非静态方法进行静态引用 从类型字符串中比较IgnoreCase(字符串)

下面的代码也会发生类似的情况

listDevs.sort(Comparator.comparing(String::compareTo));
我理解这个错误,如果我移除Comparator.comparing(如上所示),它可以正常工作

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

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


我想我错过了什么。我读过这篇文章。这是相同的场景吗?

比较器。比较
需要一个描述元素可比较属性的
函数。所以
String::length
就足够了,因为
length()
String
的一个属性,它将
String
求值为
int
(这就是为什么这里首选
comparingit

相反,
String.compareToIgnoreCase
String.compareTo
是比较方法。它们比较两个
String
对象。因此,在需要
比较器的情况下,对它们的引用就足够了,但在需要属性
函数的情况下,对它们的引用就不够了

就像你有一个工厂说“给我一个引擎,我们为你造一辆车”,你试图给他们一辆完整的车。虽然现有的汽车在预期的情况下是有效的,但把它交给工厂制造汽车是没有意义的

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

表示方法引用的编译时声明的引用类型::[TypeArguments]标识符可以以不同的方式解释

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

ReferenceType::[TypeArguments]标识符具有两个不同的算术数,n和n-1被考虑,以说明此表单引用静态方法或实例方法的可能性

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

方法接受一个。当您使用将报告错误的
String::compareToIgnoreCase
时,因为它有两个参数,一个是隐式的另一个是方法参数的比较字符串,因此它更像是一个
双函数
而不是
函数

您可以使用
比较(String::toLowerCase)
,它与
String::compareTignoreCase
相等,例如:

Comparator<String> primary = String::compareToIgnoreCase;
BiFunction<String, String, Integer> comparator1 = primary::compare;
Comparator<String> comparator2 = comparator1::apply;
// String::compareToIgnoreCase
listDevs.sort(String::compareToIgnoreCase); 

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

排序
方法需要一个
比较器

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

 listDevs.sort(Comparator.comparing(String::length));
这里也会发生同样的情况(但有点不直观):

这正是
比较器的定义-取两个字符串并返回一个int

你说这是怎么回事:
listDevs.sort(Comparator.comparing(String::length))实际上相当简单


Comparator.comparating
使用一个
函数
,将您的输入类型转换为
可比的内容。在您的例子中,接受一个
字符串
,并返回一个
整数
;这是可比的

我想说
String::compareToIgnoreCase
Comparator.comparating
所期望的方法签名不匹配。它需要
String->compariable
,但得到
(String,String)->整数
。不过,我不确定这个错误。也许Java试图将不匹配的方法解释为静态方法,以查看它是否匹配。。。顺便说一句,在Eclipse中,我得到了一个不同的、更合理的错误消息。感谢您的输入。我明白你的意思,但还是不相信。Comparator.Comparating在KeyExtractor上工作,其中整数是输入,字符串是输出。如果一个方法返回一个整数,就不会有任何问题。compareTo和length方法的返回类型完全相同。因此,如果我们从语法上讲,比较方法接受这两种方法应该没有任何问题。而且,我们同意错误消息具有误导性。不,字符串是输入,整数是输出,反之亦然。这是
length()
的情况,其中输入是调用此方法的字符串,而不是
compareTo(string)
等,它调用字符串并传递第二个字符串作为参数。当使用未绑定方法引用实例方法时,您必须学会将接收方实例作为函数参数计算。否则,无参数方法
length()。我不是故意的。我的意思是,键提取器使用字符串生成一个(整数)键,根据该键进行排序。但是对于length(),情况是一样的,整数是排序的因子,这使得两种情况相似。
length()
没有参数,而
compareTo(String)
有参数。两者都是实例方法。所以他们并不相似,但完全不同。@Vikrant Holger是对的,你可以看到第一节,然后你就知道为什么Holger说他们不相似了。
// String::compareToIgnoreCase
listDevs.sort(String::compareToIgnoreCase); 

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