带有方法参考的 Java 8 比较器

aki*_*ila 2 lambda java-8 method-reference

试图理解方法引用,但我很难理解。坚持比较器示例。

为了让我的大脑更轻松,我一直从基础开始(匿名类实现 >> laba 表达式 >> 方法引用)它是方法引用和比较器示例,我无法让它工作。

我想排序的 POJO(从一些互联网示例中提取 - mkyong)

public class Fruit{
   private int quantity;
   private String name;
   ....
}
Run Code Online (Sandbox Code Playgroud)

创建要使用的测试数据:

Fruit[] fruits = new Fruit[3];
Fruit pineapple = new Fruit("pineapple",10);
Fruit orange= new Fruit("orange",4);
Fruit kiwi= new Fruit("kiwi",15);

fruits[0] = pineapple;
fruits[1] = orange;
fruits[2] = kiwi;
Run Code Online (Sandbox Code Playgroud)

匿名排序类实现:

Comparator<Fruit> anonymousSortByname = new Comparator<Fruit>(){
     public int compare(Fruit f1,Fruit f2){
        return f1.getName().compareTo(f2.getName());
     }
};
Run Code Online (Sandbox Code Playgroud)

排序 :

Arrays.sort(fruits,anonymousSortByname);
Run Code Online (Sandbox Code Playgroud)

既然这可行,我已经明白匿名类可以转换为 lambda 表达式(前提是它们是功能接口等......)

Lambda 实现:

Comparator<Fruit> lambdaSortByname = 
 (Fruit f1,Fruit f2) -> f1.getName().compareTo(f2.getName());
Run Code Online (Sandbox Code Playgroud)

好的,到目前为止,事情是有意义的。

我的理解:“无论在哪里使用 lambda,它们可以替换为‘方法引用’”

确实在 SO 和互联网上阅读过,使用“方法引用”不是强制性的,但我的目标是理解它们 - 所以是否使用不是我的问题:)

也在这里阅读: 方法参考1这里这里。但是,当我尝试使用 Comparator 实现它时,我在方法引用方面遇到了困难。

这是我尝试过的,它给了我一个编译错误。

Comparator<Fruit> methodRefComparator = Comparator::compare;
Run Code Online (Sandbox Code Playgroud)

编译错误:

无法对非静态代码块进行静态引用

在链接中,该示例确实讨论了 Comparator 界面中的“比较”方法,但此时变得模糊....

编辑#1

根据以下评论修改了问题:

混淆是围绕Comparator 的“比较”方法如何工作的。

我确实得到了一个工作示例(通过谷歌搜索而不是我自己的理解):

首先创建了一个接受“水果”作为输入并返回一个字符串的函数。

Function<Fruit, String> funcName = (Fruit f1) -> f1.getName();
Run Code Online (Sandbox Code Playgroud)

然后将此“函数”传递给“比较器”的“比较”方法以取回所需的比较器。

Comparator<Fruit> sortByName = Comparator.comparing(funcName);
Run Code Online (Sandbox Code Playgroud)

现在排序工作:

Arrays.sort(fruits,sortByName );
Run Code Online (Sandbox Code Playgroud)

但是 .. 我无法理解它是如何工作的。我还没有提供 Comparator (f1.getName() - f2.getName()) 的实现,那么它是如何工作的?

这是否更像是编译器能够理解的合同,因为我已经为它提供了一个带有 'getName' 实现的函数,它会在返回的 Comparator 中使用它?

Hol*_*ger 5

Comparator.comparingstatic创建比较器的工厂方法,该比较器将委托给您提供的函数,用于获取要比较的属性值。基本上是这样的:

public static <T, U extends Comparable<? super U>> 
    Comparator<T> comparing(Function<? super T, ? extends U> func) {

    return (o1, o2) -> func.apply(o1).compareTo(func.apply(o2));
}
Run Code Online (Sandbox Code Playgroud)

因此,评估函数的两个参数和调用compareTo结果的逻辑就在那里。

由于这对于比较元素的属性的所有比较器都是通用的,因此将公共代码放入共享方法中是很自然的决定。这种分离也简化了你必须提供的功能,因为它只需要表达如何获取属性值。

由于这通常意味着只调用单个(getter)方法,因此它允许将函数表达为方法引用,这仅在存在单个现有方法执行您的函数应该执行的操作时才有可能,即

Arrays.sort(fruits, Comparator.comparing(Fruit::getName));
Run Code Online (Sandbox Code Playgroud)

其中Fruit::getName相当于(Fruit f) -> f.getName().

因此,并非每个 lambda 表达式都可以替换为方法引用。当 lambda 表达式由单个方法调用组成时,或者当实用程序方法帮助您将您的逻辑简化为由单个方法调用组成的函数时,您可以替换 lambda 表达式。