如果我们要对苹果集合按照重量进行排序,使用我们前面已学的lambda要怎么写呢?
苹果集合
List<Apple> apples = new ArrayList<>();
Apple a1 = new Apple("红",155);
Apple a2 = new Apple("绿",136);
Apple a3 = new Apple("红",169);
apples.add(a1);
apples.add(a2);
apples.add(a3);
要对这个苹果集合按照重量由轻到重排序,如何写?
首先要知道List本身提供了sort方法,方法需要传入一个Comparator的实现,用做排序逻辑,我们写一个lambda就可以了,不用再像以前写一个实现类或者匿名类。
System.out.println("---排序前---");
apples.forEach(System.out::println);
apples.sort((Apple a11, Apple a22) -> a11.getWeight() <= a22.getWeight()?-1:1);
System.out.println("---排序后---");
apples.forEach(System.out::println);
输出结果:
---排序前---
Apple(color=红, weight=155)
Apple(color=绿, weight=136)
Apple(color=红, weight=169)
---排序后---
Apple(color=绿, weight=136)
Apple(color=红, weight=155)
Apple(color=红, weight=169)
这是我们运用前面几节学到的知识,写出的lambda表达式实现了排序功能。
在Java8中,一个新特性就是可以直接引用一个类的普通方法,这种用法叫做:方法引用。
运用方法引用,我们将上面的排序进行一些改造:
System.out.println("---排序前---");
apples.forEach(System.out::println);
apples.sort(Comparator.comparing(Apple::getWeight).reversed());
System.out.println("---排序后---");
apples.forEach(System.out::println);
输出结果:
---排序前---
Apple(color=绿, weight=136)
Apple(color=红, weight=155)
Apple(color=红, weight=169)
---排序后---
Apple(color=红, weight=169)
Apple(color=红, weight=155)
Apple(color=绿, weight=136)
一个类中的普通成员方法,使用方法引用的方式调用写入是:
类名::方法名
类名和方法名中间由两个冒号。
上面的例子中,Comparator.comparing(Apple::getWeight),使用了Comparator类提供的comparing方法,方法参数是:Apple::getWeight,是不是有点不可思议,先看一下comparing方法的源码;
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
我们可以看到最重要的一行:
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2))
其实这还是我们第一种写法,只不过,通过方法引用,进行了简化,相当于一个语法糖,在源码中,还是需要两个参数,来进行比较,而参数keyExtractor,则可以转化为:c1.getWeight().compareTo.c2.getWeight()。
源码中的:
keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2))
可以转化为:
c1.getWeight().compareTo.c2.getWeight()
其实就是这样的效果,这也就是我们前面所说的:行为参数化。我们的参数是一个getWeight()的行为,而不是像传统方法,c1.getWeight()=155,拿这个155当作参数,传入方法。
在本文的第二个例子中:
Comparator.comparing(Apple::getWeight).reversed()
我们最后还用到了reversed(),相当于是对排序结果反转。
方法引用,并不仅仅是上面这一种使用方法,主要由以下几种:
实例上的实例方法引用 | instanceReference::methodName |
父类实例方法引用 | super::methodName |
类型上的实例方法引用 | ClassName::methodName |
构造方法引用 | Class::new |
数组构造方法引用 | TypeName[]:new |
静态方法 | ClassName::methodName |