Vik*_*ant 9 java static-methods comparator java-8 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
Run Code Online (Sandbox Code Playgroud)
但是(当expermient)当我尝试写
listDevs.sort(Comparator.comparing(String::compareToIgnoreCase));
Run Code Online (Sandbox Code Playgroud)
编译器抛出错误
无法从类型String中对非静态方法compareToIgnoreCase(String)进行静态引用
类似的情况发生在下面的代码中
listDevs.sort(Comparator.comparing(String::compareTo));
Run Code Online (Sandbox Code Playgroud)
我理解错误,如果我删除Comparator.comparing(如上所示)它工作正常.
但我的观点是,这条线如何运作?
listDevs.sort(Comparator.comparing(字符串::长度));
我相信我错过了一些东西.我已经读过这个帖子了.这是同样的情况吗?
Hol*_*ger 13
Comparator.comparing期望一个Function描述元素的可比属性.因此,评估a 到a的属性String::length就足够了(这就是为什么这里更好).length()StringStringintcomparingInt
相比之下,String.compareToIgnoreCase和String.compareTo是比较的方法.他们比较两个String对象.因此,在Comparator预期的情况下,对它们的引用是足够的,但不是Function预期的属性.
这就像你有一个工厂说"Gimme是一个发动机,我们为你制造一辆汽车",你正试图给他们一辆完整的汽车.虽然现有的汽车在预计有车的情况下是有效的,但将其传递到工厂制造汽车是没有意义的.
不幸的是,当前的编译器实现在报告功能签名错误方面非常糟糕.当签名不匹配时,您几乎总会看到诸如"无法对非静态方法进行静态引用..."之类的消息.
JLS说ReferenceType :: [TypeArguments] 标识符的方法引用的编译时声明可以用不同的方式解释。
给定具有 n 个参数的目标函数类型,确定一组可能适用的方法:
ReferenceType :: [TypeArguments] 标识符有两个不同的参数,n 和 n-1,被考虑,以解释这种形式引用静态方法或实例方法的可能性。
ReferenceType :: [TypeArguments] Identifier 形式的方法引用表达式可以用不同的方式解释。如果 Identifier 引用一个实例方法,那么与Identifier 引用静态方法相比,隐式 lambda 表达式具有一个额外的this类型参数。ReferenceType 可能有两种适用的方法,因此上述搜索算法分别识别它们,因为每种情况都有不同的参数类型。
Comparator.comparing方法接受一个Function<T,R extends Comparable<? 超级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;
Run Code Online (Sandbox Code Playgroud)
Stream.sort方法接受一个Comparator,而 Comparator 更像是一个,BiFunction<T,T,Integer>所以它与String::compareToIgnoreCase. 另一方面,它们可以互换。例如:
Comparator<String> primary = String::compareToIgnoreCase;
BiFunction<String, String, Integer> comparator1 = primary::compare;
Comparator<String> comparator2 = comparator1::apply;
Run Code Online (Sandbox Code Playgroud)
您可以comparing(String::toLowerCase)改用,它等同于String::compareToIgnoreCase,例如:
// String::compareToIgnoreCase
listDevs.sort(String::compareToIgnoreCase);
// comparing(String::toLowerCase)
listDevs.sort(comparing(String::toLowerCase))
Run Code Online (Sandbox Code Playgroud)
该sort方法预计a Comparator.
当你这样做时,你确实提供了一个.
listDevs.sort(Comparator.comparing(String::length));
Run Code Online (Sandbox Code Playgroud)
这里也发生了同样的事情(但有点不直观):
listDevs.sort(String::compareToIgnoreCase)
listDevs.sort((left, right) -> left.compareToIgnoreCase(right)); // same thing as above
Run Code Online (Sandbox Code Playgroud)
这正是a的定义Comparator- 取两个字符串并返回一个int.
你说它是如何工作的线:listDevs.sort(Comparator.comparing(String::length));实际上非常简单.
Comparator.comparing采取一种Function方式将您的输入类型转换为Comparable.在你的情况下,取一个String并返回一个Integer; 这是可比的.