Lambda 带方法引用的Java8比较器

Lambda 带方法引用的Java8比较器,lambda,java-8,method-reference,Lambda,Java 8,Method Reference,试图理解方法引用,但我很难理解。 坚持使用比较器示例 为了让我的大脑更轻松,我一直从基础开始(匿名类实现>>lamba表达式>>方法引用) 正是由于方法引用和比较器示例,我无法让它工作 我想要排序的POJO(从一些互联网示例中选取-mkyong) 创建要使用的测试数据: Fruit[] fruits = new Fruit[3]; Fruit pineapple = new Fruit("pineapple",10); Fruit orange= new Fruit(&quo

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

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

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

创建要使用的测试数据:

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;
匿名排序类实现:

Comparator<Fruit> anonymousSortByname = new Comparator<Fruit>(){
     public int compare(Fruit f1,Fruit f2){
        return f1.getName().compareTo(f2.getName());
     }
};
Comparator<Fruit> lambdaSortByname = 
 (Fruit f1,Fruit f2) -> f1.getName().compareTo(f2.getName());
现在,我已经了解到匿名类可以转换为lambda表达式(只要它们是函数接口等…)

Lambda实现:

Comparator<Fruit> anonymousSortByname = new Comparator<Fruit>(){
     public int compare(Fruit f1,Fruit f2){
        return f1.getName().compareTo(f2.getName());
     }
};
Comparator<Fruit> lambdaSortByname = 
 (Fruit f1,Fruit f2) -> f1.getName().compareTo(f2.getName());
但是。。我无法理解它是如何工作的。 我没有提供比较器的实现(f1.getName()-f2.getName()),那么它是如何工作的呢


这更像是一个契约,编译器能够理解,因为我为它提供了一个带有“getName”实现的函数,它会在返回的比较器中使用它吗?

使用->时,可以在函数中使用变量。 当您使用::时,函数将使用默认变量


您的源代码编译失败,因为函数compare是用2个变量实现的,而您的变量为0

使用->时,可以在函数中使用变量。 当您使用::时,函数将使用默认变量

您的源代码编译失败,因为函数compare是用2个变量实现的,而您的变量为0

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

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));
}
其中
Fruit::getName
相当于
(Fruit f)->f.getName()

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

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

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));
}
其中
Fruit::getName
相当于
(Fruit f)->f.getName()


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

感谢您提供了详细的解释。如果我以Fruit::getQty的形式提供函数实现,它似乎也可以工作。在传统的实现中,我会将其写为f1.getQty()-f2.getQty,但“比较”实现会对其进行比较。对这一点感到困惑的是,永远不要在比较器实现中使用减号。它可能适用于某些受限的值范围,但通常情况下,负号可能会溢出。除此之外,当您将
int
返回方法绑定到
函数
时,它将使用自动装箱,即您得到一个
函数
,并且通用的
比较
方法可以返回一个函数,该函数将调用
整数
对象上的
比较
。您可以使用
comparingit(ToIntFunction)
来避免装箱。然后,它将执行
(Fruit f1,Fruit f2)->Integer.compare(f1.getqy(),f2.getqy())
,这也是您应该执行的操作,而不是使用减号。感谢您提供详细的解释。如果我以Fruit::getQty的形式提供函数实现,它似乎也可以工作。在传统的实现中,我会将其写为f1.getQty()-f2.getQty,但“比较”实现会对其进行比较。对这一点感到困惑的是,永远不要在比较器实现中使用减号。它可能适用于某些受限的值范围,但通常情况下,负号可能会溢出。除此之外,当您将
int
返回方法绑定到
函数
时,它将使用自动装箱,即您得到一个
函数
,并且通用的
比较
方法可以返回一个函数,该函数将调用
整数
对象上的
比较
。您可以使用
comparingit(ToIntFunction)
来避免装箱。然后,它将执行
(Fruit f1,Fruit f2)->Integer.compare(f1.getQty(),f2.getQty())
,这也是您应该执行的操作,而不是使用减号。
Comparator<Fruit> sortByName = Comparator.comparing(funcName);
Arrays.sort(fruits,sortByName );
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));
}
Arrays.sort(fruits, Comparator.comparing(Fruit::getName));