需求1. 按照产品的重量进行升序排序java
此处使用「匿名内部类」的设计,但掺杂了较多的语法噪声,引入了没必要要的复杂度。express
Collections.sort(repo, new Comparator<Product>() { @Override public int compare(Product p1, Product p2) { return p1.getWeight().compareTo(p2.getWeight()); } });
使用Lambda
表达式,能够进一步消除语法噪声,简化设计。app
Collections.sort(repo, (Product p1, Product p2) -> p1.getWeight().compareTo(p2.getWeight()));
也就是说,Lambda
其本质是「匿名内部类」的一种「语法糖」表示,存在以下3
个方面的特征:ide
Anonymous Function
:匿名的函数函数
Passed Around
:可做为参数或返回值进行传递,甚至能够自由地存储在变量中工具
Concise
:相对于匿名内部类的样板代码(Boilerplate),Lambda更加简洁漂亮this
借助编译器「类型推演」的能力,能够进一步简化Lambda
表达式。设计
Collections.sort(repo, (p1, p2) -> p1.getWeight().compareTo(p2.getWeight()));
形式1:(parameters) -> expression
code
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 <T> void sort(List<? extends T> l, Comparator<? super T> c) { l.sort(c); } }
这样的设计是反OO
,为此能够将其sort
搬迁至List
接口中去。
public interface List<E> extends Collection<E> { 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<T> { int compare(T o1, T o2); default Comparator<T> reversed() { return Collections.reverseOrder(this); } static <T, U extends Comparable<? super U>> Comparator<T> comparing( Function<? super T, ? extends U> extractor) { return (c1, c2) -> extractor.apply(c1) .compareTo(extractor.apply(c2)); } }
其中,Comprator.compring
的实现稍微有点复杂。
comparing
是一个静态工厂方法,它生产一个Comparator<T>
类型的实例;
comparing
是一个高阶函数;
接受一个函数:Function<? super T, ? extends U> extractor
返回一个函数:Comparator<T>
comparing
是一个语法糖,结合「方法引用」的机制,极大地改善了用户接口的表达力;