
Java 開發者的函數式程式設計(4)不可變特性
Java 開發者的函數式程式設計(3)List 處理模式 << 前情 函數式程式設計的重要特性之一就是,變數不可變(Immutable)。技術上來說,純函數式語言沒有變數,例如,如果在 Haskell 寫下 可變的(Mutable)變數會有什麼問題嗎?如果程式流程中有可變的變數,因為要改變它們的值太簡單了,反而使得問題難以切割為子問題;使用了非區域變數的方法可能有副作用,也就是說,在給定相同引數的情況下,方法可能傳回不同的結果,因為這些方法有看不到的輸入與輸出;如果物件狀態可變,物件就會是副作用的集合體,因為值域就相當於方法的非區域變數,追蹤變數的難度會提昇至追蹤物件狀態的層級,如果物件是運用在並行的場合,那麼要處理物件狀態的同步問題就會變得困難。 純函數式語言中,不可變是基本的特性,可強制我們將冗長的程式流程分解為較小的子流程;方法使用了不可變的非區域變數並不會有副作用,物件不會是副作用集合體,也就不會有執行緒同步處理的問題。 對於習慣命令式風格的程式設計者來說,要想像不可變的變數可能會有點難度,不過也沒有這麼困難。有發現嗎?在先前文章的範例中,我們沒有改變任何一個變數值或物件狀態。我們映射了首元素,然後將尾清單再傳給 一旦你無法使用可變的變數,那麼程式流程就會發生變化。 例如,你無法使用迴圈,像是 可以看到,一旦變數不可變,就會強制你將問題分解為子問題,這是因為你無從選擇,不可變特性是個強制找出邏輯泥塊的方式,並使用方法將之提煉出來,因此,你無法使用迴圈,遞迴會是較好的替代方案,你必須使用方法來封裝 String nickName = getNickName("Justin"); if(nickName == null) { nickName = "Guest"; } 則可以定義一個 static String getOrElse(String original, String replacement) { if(original == null) { return replacement; } else { return original; } } 那麼,你就可以使用 String nickName = getOrElse(getNickName("Justin"), "Guest"); 事實上,Java 是有個語法,類似函數式語言中常用的 String name = getNickName("Justin"); String nickName = (name != null ? name : "Guest"); 在 Java 開發者的函數式程式設計(1) 中,我們看過《Functional Programming for Java Developers in Functional Programming》這本書第一章〈Why Function Programming?〉中列出的要點,因為現在我們已經知道什麼是 代數資料型態,看過幾個 List 處理模式,也知道不可變特性了,現在可以稍微解釋一下那幾個要點的意義:
因為不可變特性,函數式程式設計不會有副作用。
函數式程式設計定義與使用代數資料型態,代數資料型態易於處理具有規律性的問題,像是資料處理問題。
在進行函數式程式設計時,你必須將問題分解為子問題,一旦有了處理子問題的方案,就可以將這些方案,運用於其它具有相同子問題的問題中。
因為程式碼變得更簡明,就可以找到更高階的抽象,也就會擁有更多相似問題的解決方案,工作上就會越來越有效率。
一旦熟悉函數式程式設計,該做的事情,就是將問題分解為子問題,幾乎都是這樣。 不過,就如同在 Java 開發者的函數式程式設計(1) 中看過的,如果你使用的語言並非純函數式語言的話,像是 Java,切勿不假思索地直接套用所有函數式的概念。在下一篇的文章中,我們會回到實際的 Java 運用,看看能從函數式程式設計中擷取哪些觀念。 |