
Java 開發者的函數式程式設計(5)JDK8 預設方法
Java 開發者的函數式程式設計(4)不可變特性 << 前情 讓我們回歸到 Java 的現實世界吧!Java 的語法是用來定義抽象資料型態,以命令式風格來撰寫程式,它允許可變動的變數與物件,所以之前的文章是純屬娛樂嗎?嗯…如果有些聰明的傢伙已經實作了那些好用的方法,像是 map(list(1, 2, 3, 4, 5), x -> x + 1); 將清單中小於三的元素過濾出來就可以撰寫為: filter(list(1, 2, 3, 4, 5), x -> x > 3); 要加總清單元素就可以撰寫為: reduce(list(1, 2, 3, 4, 5), (sum, x) -> sum + x, 0); 沒錯!幾乎每個 Java 開發者都聽過這個原則 – 根據介面撰寫程式,而不是根據實作。也許那些聰明的傢伙是用命令式風格來實作 …有第一級函數的編程語言讓你找到更多抽象化的機會… 即使你最後仍是以命令式風格來撰寫程式,你還是可以函數式地思考。在撰寫程式時,函數式地思考總能讓你有新的想法或者是方向,這就是為什麼 Simon Peyton Jones 這麼提到… …純函數式領域中學到的觀念與想法,可能給主流領域帶來資訊,帶來啟發… 當然,確實有群聰明的傢伙實作了那些函數式程式語言中常用到的方法,然而這邊的問題是,這些方法要放在哪?例如,像 List<String> names = ...; names.filter(s -> s.length() < 3) .forEach(s -> out.println(s)); 這樣的風格在 Java 中看起來,會比以下風格更有表達性一些: forEach(filter(names, s -> s.length() < 3), s -> out.println(s)); 只是,我們有辦法在 JDK8 最後採取的策略是,直接演化 預設方法的實例之一,就是定義在 package java.lang; import java.util.Iterator; import java.util.Objects; import java.util.function.Consumer; @FunctionalInterface public interface Iterable<T> { Iterator<T> iterator(); default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } }
List<String> names = ...; names.forEach( name -> out.println(name.toUpperCase()) ); 因為 public interface Comparable<T> { int compareTo(T that); default boolean lessThan(T that) { return compareTo(that) < 0; } default boolean lessOrEquals(T that) { return compareTo(that) <= 0; } default boolean greaterThan(T that) { return compareTo(that) > 0; } ... } 如果有個 public class Ball implements Comparable<Ball> { private int radius; ... public int compareTo(Ball that) { return this.radius - that.radius; } } 這麼一來,每個 當然,有關預設方法還有一些細節,你可以看看 State of the Lambda v4 這些文章瞭解更多細節。我們先回到先前看過的例子,我們想要有以下的程式碼撰寫風格: List<String> names = ...; names.filter(s -> s.length() < 3) .forEach(s -> out.println(s)); 不過在 JDK8 中,我們實際上必須撰寫為: List<String> names = ...; names.stream() .filter(s -> s.length() < 3) .forEach(s -> out.println(s)); 為什麼要多那個 |