你可以在 Google Play 或 Pubu 上取得收錄本系列文章的 Java Lambda Tutorial 電子書。
在 認識 Lambda/Closure 系列 中,我談到了什麼是 Lambda/Closure、不同程式語言的支援方式,以及為什麼 JDK8 採用了目前的 Lambda 語法。想要善用 Lambda,可以從其它已具備一級函式的語言中借鏡,實際上在這些語言中,許多一級函式的概念是直接或間接來自於函數式程式設計(Functional programming),更進一步地,函數式程式設計的模型是基於 Lambda 演算。若能一步步深入這些概念,就更能夠瞭解 Lambda/Closure 的實際應用場合。
在 認識 Lambda/Closure(6)一級函式與 Lambda 演算 中,曾經簡介過 Lambda 演算的基本概念,而從這篇文章開始,我會介紹何謂函數式程式設計,以及在 Java 中如何進行函數式程式設計。不過,為什麼要認識函數式程式設計?
在 〈你的程式語言可以這樣做嗎?〉(Can Your Programming Language Do This?)中,Joel Spolsky 說過:
...有第一級函數的編程語言讓你找到更多抽象化的機會...
在《編程的領尖對話》(Coders at Work) 這本書中,Simon Peyton Jones 提到:...純函數式領域中學到的觀念與想法,可能給主流領域帶來資訊,帶來啟發...
在 《Java 開發者的函數式程式設計》(Functional Programming for Java Developers)這本書中,Dean Wampler 在第一章〈為何要函數式程式設計?〉(Why Function Programming?)列出了五個看法:- 我想寫好並行程式(Concurrent program)
- 大部份程式只是在做資料處理問題(Data Management Problem)
- 函數式程式設計更模組化
- 工作上我要更有效率
- 函數式程式設計是返樸歸真
在數學上,費波那西數列是以遞歸的方法來定義:
F0 = 0 F1 = 1 Fn = Fn-1 + Fn-2
在命令式程式設計(Imperative programming)中,你必須告訴電腦求解問題的每個步驟。例如,可以使用 Java 實作一個如下的static 方法:
      static int fib(int n) {
    if(n == 0 || n == 1) {
        return n;
    }
    int a = 0;
    int b = 1;
    for(int i = 2; i <= n; i++) {
        int tmp = b;
        b = a + b;
        a = tmp;
    }
    return b;
}static int fib(int n) {
    if(n == 0 || n == 1) {
        return n;
    }
    return fib(n - 1) + fib(n - 2);
}fib 0 = 0
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)fib 0 = 0
fib 1 = 1
fib n = addPrevsRecusivelyUntilCounterIsN (fib 1) (fib 0) 2 n
addPrevsRecusivelyUntilCounterIsN prev1 prev2 counter n
    | counter == n = result
    | otherwise = addPrevsRecusivelyUntilCounterIsN result prev1 (counter + 1) n
    where result = prev1 + prev2這邊的重點在於,如果使用的語言並非函數式語言,你不能不假思索地直接套用函數式設計的所有概念,否則就有可能事倍功半,可讀性與效能都會變差。如果你想進行純函數式程式設計,使用函數式語言會比較好,像是 Scala、Haskell 等。
那麼使用非函數式語言,要怎麼撰寫函數式風格的程式碼呢?只有先瞭解函數式設計的本質,才可以讓我們明瞭,如何適當地擷取函數式設計的概念。
函數式程式設計中一個顯而易見的外在形式就是遞迴,不過,遞迴不是重點,將問題分解為子問題才是重點,通常子問題在分解之後,自然而然就會形成遞迴。以加總數列為例,以命令式方式求解的話,就必須要求電腦將變數
sum 初始為 0,取得數列的下個元素,將元素加至 sum,重複這個動作直到所有元素都迭代過為止,接著傳回 sum。
      static int sum(int... nums) {
    int sum = 0;
    for(int num : nums) {
        sum += num;
    }
    return sum;
}x 而尾數列為 xs 的加總為何?那就是 x 與 xs 的總和進行加總!使用 Haskell 寫下這兩個子問題的話就會是…
      sum [] = 0
sum (x:xs) = x + sum xs「等一下!等一下!現在是在討論 Java 啊!別老是寫 Haskell...XD」好的!不過呢!物件導向程式設計是 Java 的主流典範,在使用 Java 以函數式方式求解之前,得先來談談代數資料型態(Algebraic data type)、處理數列時共通的模式、以及不可變特性(Immutability),這會在之前的文章中分別探討...

