在 Java 出現 Lambda 後,API 的實作方式也改變了,像是模板方法模式 (Template method pattern),現在的作法多用靜態工廠或是構造方法來達到同樣的效果。以 LinkedHashMap 為例,在覆寫 removeEldestEntry 方法後,新增新元素後,最早之前的元素會被移除,當作 cache 的機制。
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
假設欲使用 Lambda 來設計上述的方法,讓 LinkedHashMap 在生成時傳入該方法,可以自行定義一個新的函數介面,這樣的作法沒有問題。但在 package java.util.Function 中,已經定義大量的標準函數介面,所以在撰寫客製的函數介面前,應優先考慮是否有符合的標準函數介面。EldestEntryRemovalFunction<K,V> 回傳的是 boolean 屬於 predicate,又因傳入的參數有兩個,所以使用 BiPredicate 便能取代。
@FunctionalInterface
interface EldestEntryRemovalFunction<K,V> {
boolean remove(Map<K,V> map, Map.Entry<K,V> eldest);
}
BiPredicate<Map<K,V>, Map.Entry<K,V>>
下面為常見的函數介面定義,Bi- 開頭的就代表傳入的參數有兩個,像是 BiConsumer、BiFunction 及 BiPredicate。- Operator 表示其回傳結果與傳入參數為同一類型的函數
- Predicate 表示傳入一參數然後回傳為 boolean 的函數
- Function 表示傳入類型為 T 回傳類型為 R 的函數
- Supplier 表示沒有傳入參數但回傳一個 T 類型的函數
- Consumer 表示傳入一個參數但沒有任何回傳
介面 | 方法 | 範例 |
---|---|---|
UnaryOperator | T apply(T t) | String::toLowerCase |
BinaryOperator | T apply(T t1, T t2) | BigInteger::add |
Predicate | boolean test(T t) | Collection::isEmpty |
Function<T,R> | R apply(T t) | Arrays::asList |
Supplier | T get() | Instant::now |
Consumer | void accept(T t) | System.out::println |
回到之前談到的 Comparator<T>
@FunctionalInterface
public interface Comparator {
int compare(T o1, T o2);
}
@FunctionalInterface
public interface ToIntBiFunction {
int applyAsInt(T t, U u);
}
轉載請註明原文網址 https://cookieandcoketw.blogspot.com/2021/03/effective-java-44-functional-interfaces.html
沒有留言:
張貼留言