Java 8 初探 - Closure

2024/04/25閱讀時間約 5 分鐘
此為過去的舊文,2014 年 3 月 30 日初次發表於 logdown。

印象中,在官方的《Java Magazine》雙月刊中,已經探討過好幾回的 Java 8 及 Lambda,但似乎鮮少討論到 Closure,稍微快速翻找一下,在 2013 的七八月號上有看到介紹 Lambda 的文章中討論到Closure。我想主要的原因應該是

  1. 在沒有 Lambda 前,anonymous class 本身就可以捕捉變數,只是捕捉的變數自動被視為 final。
  2. Java 的 Lambda 所捕獲的變數,某種程度還是不夠自由。無法完整重現自由變數,所以沒有特別去宣傳 Java Lambda 和 Closure 之間的關係。

翻了一下 Wikipedia 上對 Closure 的描述 (我想參考 Wikipedia 應該比參考某些專論programming languages的書要方便一些),在 Closure 內可以對自由變數的做任何變數上的操作,包含更動數值,這一點在許多語言的支援上也不見得完全相同。

以最近工作上常寫的 Objective C 來說,Apple 官方文件給了幾個例子,官方文件以儲存空間的角度去探討捕捉變數,這是對記憶體位置特別敏感的語言某種程度上的痛處,不過這裡就用比較抽象的方式解釋 code block 對於捕捉變數的處理。預設上,code block 捕捉變數的值,也就是說在捕捉後對變數的更動在 code block 內是看不見的,所以下例中 NSLog 所顯示的結果是 42 而不是 84

若希望 code block 捕捉變數而不是僅僅數值的話,需像下例在被捕捉的變數宣告上加上 __block 的修飾字,此時 NSLog 顯示的結果就會是 84,因為當 code block 執行時 (第6行),捕捉的變數 anInteger 已經變成 84 了 (第5行)。

__block 修飾字讓 code block 捕捉變數本身,所以也可以更動變數的值,因此下例中 NSLog 是在 callback() 執行後才顯示 anInteger 的值,結果是 100。我個人覺得這樣的處理有好有壞,就抽象程度上,額外需要 __block 修飾字讓工程師還是意識到記憶體位置的存在,這是降低語言的抽象程度(不直覺)。

Objective C 可用這些修飾字針對效能提升最佳化編譯結果,不但能同時提供唯讀/讀寫的捕捉變數,另外也提供編譯期間的檢查,例如沒用 __block 但卻在 code block 中變更變數值會視為錯誤,某種程度上我覺得是還不錯的設計。

好,該回到 Java 本身了,沒有 Lambda 前,anonymous class 可以像下例那樣捕捉 scope 中可見的變數 x,但最大問題是捕捉的變數 x 實際上是 final 變數 (effectively final),所以被註解的 x = 48; 若取消註解會被視為編譯錯誤。

即使改成用 Lambda 也是一樣的,如下例,在 Lambda 內 x 依舊是 final 變數,無法更動變數值,取消 x = 48; 的註解依然會是編譯錯誤。

Java 的 final 修飾字僅限制無法改變變數值,但若變數是個物件,呼叫物件 method 卻是允許的,即使該 method 會改變物件內的狀態都是允許的,所以 anonymous class 的範例可以改寫如下。同樣,取消 x = new AtomicInteger(48); 的註解會得到編譯錯誤,但用 x.set(48); 可以實際改變 x 的值 (這在 Objective C 也是一樣)。

所以,Lambda 的例子也可以改寫如下。很可惜,能夠 Autoboxing and Unboxing 的資料型態,例如:Integer,都是 immutable 的資料型態,使用上無法像 JavaScript 這類將基礎型別都視為物件的語言那樣方便。不過,某種程度上有點像自由變數了。

最後,Java 8 雖然支援 Lambda,但我覺得 Closure 某種程度上還不稱不上是 Java 的第一級居民,而且如Java 8 初探 - Lambda所述,為了方便測試,除非是只有一行或是非常簡單的程式碼 (too simple to break) 不用擔心測試的問題外,我還是比較喜歡寫一些小而易測的 class,而不是使用 Lambda,至於捕捉變數,透過建構子將變數帶入物件也是一種方式。至於什麼情況下會常寫只有一行或是非常簡單的 Lambda 呢?我覺得 Stream,新的 Collection API 開啟了相當大的可能性。

51會員
100內容數
這是從 Medium 開始的一個專題,主要是想用輕鬆閒談的方式,分享這幾年軟體開發的心得,原本比較侷限於軟體架構,但這幾年的文章不僅限於架構,也聊不少流程相關的心得,所以趁換平台,順勢換成閒談軟體設計。
留言0
查看全部
發表第一個留言支持創作者!