以下是我的代码段的两行:
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帖子。这是同样的情况吗?
答案 0 :(得分:13)
Comparator.comparing
需要一个Function
来描述元素的可比属性。所以String::length
就足够了length()
是String
评估String
到int
的属性(这就是为什么comparingInt
更可取的原因)
相比之下,String.compareToIgnoreCase
和String.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))