需求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
是一個語法糖,結合「方法引用」的機制,極大地改善了用戶接口的表達力;