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