終於要開始討論 Java 的 Lambda/Closure 了!不過這邊會先討論 2009 年提出的 舊草案,討論這份舊草案,有助於我們瞭解為什麼 Lambda/Closure 會演變至今天 JDK8 所採取的形式。
如果打算對一列整數排序,在 JDK8 之前,你也許會寫下以下的程式碼:
// asList 與 sort 方法是從 Arrays 與 Collections 中 static import 而來
List<Integer> numbers = asList(3, 2, 6, 4);
sort(numbers, new Comparator<Integer>() {
    public int compare(Integer n1, Integer n2) {
        return -n1.compareTo(n2);
    }
});sort 方法兩個數字的順序為何。目前 Java 因為沒有一級函式,所以你必須提供 Comparator 實例。以上範例使用了匿名類別來建立了 Comparator 實例,不過冗長的語法,讓開發者較難一眼就看出打算令 sort 方法做些什麼。如果使用個適當的變數名稱,會讓可讀性好一些。例如:
      List<Integer> numbers = asList(3, 2, 6, 4);
Comparator<Integer> descending = new Comparator<Integer>() {
    public int compare(Integer n1, Integer n2) {
        return -n1.compareTo(n2);
    }
};
sort(numbers, descending);sort 方法做些什麼,不過使用匿名類別還是有點煩人。如果能使用 JDK8 採用的 Lambda/Closure 語法的話,程式碼可以更短更簡潔。例如:
      List<Integer> numbers = asList(3, 2, 6, 4);
sort(numbers, (n1, n2) -> -n1.compareTo(n2));今日你撰寫程式碼的難易度,取決於其周遭程式碼閱讀時的難易度。
匿名類別冗長的語法不是唯一的問題。如果匿名類別打算捕捉區域變數的話,該變數必須被宣告為final。例如:
      public static FactorProducer createFactorProducer(max) {
final int[] primes = ...;
FactorProducer producer = new FactorProducer() {
        public int factor() {
            ...
            while(pow(primes[i], 2)) {
                ...
            }
        }
    };
    return producer;
}final 加以修飾。被捕捉的變數(而不是它參考的物件)就會是唯讀的。實際在底層中,Java 編譯器會建立在匿名類別中建立新的變數,將原本 final 變數的參考複製給新變數。你並非真的捕捉了外部的區域變數,你只是有一個新變數並被複製的參考值。匿名類別中的
final 有什麼問題?或者說,Closure 中只能唯讀的變數有什麼問題?這個問題的答案取決於你打算用 Closure 做些什麼?在 認識 Lambda/Closure(二) 中,我們看過 Closure 在 JavaScript 中可用來模擬 private 特性,在這種情況下,可寫的閒置變數(Free varialbe)是必要的。不過可寫的閒置變數基本上暗示著,執行流程會是循序的(Serial)。像是這段 JavaScript:
      var sum = 0;
[1, 2, 3, 4, 5].forEach(function(elem) {
    sum += elem;
});在 2009 年的一份草案中,要定義 Lambda,以及要宣告一個可接受 Lambda 的變數,會是像這樣:
#int(int) doubler = #(int x)(2 * x);
doubler.(3) // 呼叫 Lambdaint doubler(int x) {
    return 2 * x;
}
doubler(3);int 參數並傳回 int 值的 Lambda 可以如下定義:
      #int(int, int) sum = #(int x, int y)(x + y)int sum(int x, int y) {
    return x + y;
}bubbleSort 函式,大概會像是:
      def bubbleSort(int[] arr, #boolean(int, int) order) {
    ...
    boolean o = order.(a, b);
    ...
}
int[] arr = new int[] {2, 5, 1, 7, 8};
bubbleSort(arr, #(int a, int b)(a > b));##int(int)(int) sum = #(int x)(#(int y)(x + y));幸運地,JDK8 沒有採取這種特定函式型態的語法,它使用單一抽象方法(Single abstract method)型態,也就是之後被稱為函式介面(Functional interface)的方式,而這是之後的文章中將要探討的內容。

