Lambda的本质
需求1. 按照产品的重量进行升序排序
此处使用「匿名内部类」的设计,但掺杂了较多的语法噪声,引入了不必要的复杂度。
Collections.sort(repo, new Comparator() {
@Override
public int compare(Product p1, Product p2) {
return p1.getWeight().compareTo(p2.getWeight());
}
});
使用Lambda表达式,可以进一步消除语法噪声,简化设计。
Collections.sort(repo, (Product p1, Product p2) ->
p1.getWeight().compareTo(p2.getWeight()));
也就是说,Lambda其本质是「匿名内部类」的一种「语法糖」表示,存在如下3个方面的特征:
Anonymous Function:匿名的函数
Passed Around:可作为参数或返回值进行传递,甚至可以自由地存储在变量中
Concise:相对于匿名内部类的样板代码(Boilerplate),Lambda更加简洁漂亮
类型推演
借助编译器「类型推演」的能力,可以进一步简化Lambda表达式。
Collections.sort(repo, (p1, p2) ->
p1.getWeight().compareTo(p2.getWeight()));
Lambda的形式
形式1:(parameters) -> expression
Collections.sort(repo, (p1, p2) ->
p1.getWeight().compareTo(p2.getWeight()));
形式2:(parameters) -> { statements; }
Collections.sort(repo, (p1, p2) -> {
return p1.getWeight().compareTo(p2.getWeight());
});
默认方法
先看看java.util.Collections.sort的实现,其中java.util.Collections是一个典型的「工具类」。
public final class Collectins {
private Collectins() {
}
public static void sort(List extends T> l, Comparator super T> c) {
l.sort(c);
}
}
这样的设计是反OO,为此可以将其sort搬迁至List接口中去。
public interface List extends Collection {
default void sort(Comparator super E> c) {
...
}
...
}
default方法类似于C++的虚函数。从某种意义上看,default的引入使得Java又重新回到了「多重继承」的怀抱,为设计带来了更大的弹性。
为此,设计可重构为更加符合OO的风格。
repo.sort((p1, p2) -> p1.getWeight().compareTo(p2.getWeight()));
方法引用
借助Comparator.comparing的工厂方法,结合「方法引用」可进一步提高代码的可读性。
import static java.util.Comparator.comparing;
repo.sort(comparing(Product::getWeight));
方法引用其本质是具有单一方法调用的lambda表达式的「语法糖」表示。
级联方法
需求2. 按照产品的重量降序排序
repo.sort(comparing(Product::getWeight)
.reversed());
.thenComparing(Product::getCountry));
需求3. 如果重量相同,则按照出厂国的自然序排序
repo.sort(comparing(Product::getWeight)
.reversed()
.thenComparing(Product::getCountry));
深入理解Comparator
有且仅有一个抽象方法的接口,称为「函数式接口」,使用@FunctionalInterface的注解标识。函数式接口中「抽象方法」描述了Lambda表达式的「原型」。
() -> {}也是一个合法的Lambda表达式,与Runnable接口相匹配。
也就是说,一个「函数式接口」可包含如下元素:
Abstract Method:有且仅有一个抽象方法
Default Methods:0个或多个默认方法
Static Methods: 0个或多个静态方法
对照前面的列子,可洞悉Comparator设计的巧妙。
repo.sort(comparing(Product::getWeight)
.reversed());
其中,Comparator就是一个典型的函数式接口。通过「方法级联」设计了一套简单的Comparator的DSL,增强了用户的表达力。
@FunctionalInterface
public interface Comparator {
int compare(T o1, T o2);
default Comparator reversed() {
return Collections.reverseOrder(this);
}
static >
Comparator comparing(
Function super T, ? extends U> extractor) {
return (c1, c2) -> extractor.apply(c1)
.compareTo(extractor.apply(c2));
}
}
其中,Comprator.compring的实现稍微有点复杂。
comparing是一个静态工厂方法,它生产一个Comparator类型的实例;
comparing是一个高阶函数;
接受一个函数:Function super T, ? extends U> extractor
返回一个函数:Comparator
comparing是一个语法糖,结合「方法引用」的机制,极大地改善了用户接口的表达力;