Effective Java Item 42:偏好使用 Lambda 表達式取代匿名類別
整理 Effective Java 書中 Item 42: Prefer lambda expressions to anonymous classes 心得筆記
主旨
在 Java 8 之前,若要實作一個函式物件(function object),通常會使用匿名類別。但寫法冗長、閱讀不易。Java 8 引入 Lambda 表達式後,可以用更簡潔的語法來表示這些功能。這篇文章會說明為什麼你應該「偏好使用 Lambda」,並補充 Lambda 和匿名類別的異同、注意事項,以及何時該避免使用 Lambda。
點出問題:匿名類別太冗長
匿名類別是 Java 中實作單一抽象方法介面的傳統方式,但它的語法很繁瑣。例如,我們想根據字串長度排序清單:
整個 new Comparator<>()
的寫法、方法宣告等,都會佔掉不少篇幅。如果我們只是想排序,這段程式碼的意圖反而被冗長的語法蓋掉了。
劃重點:Lambda 更精簡、更清楚
Lambda 的寫法就簡潔多了:
這邊可以省略類型,因為編譯器會自動推斷。Lambda 主要是為了解決像這種「單一抽象方法介面」的問題,這類介面稱作 Functional Interface。Java 內建了很多這類介面,例如:
Comparator<T>
Runnable
Callable<V>
Function<T, R>
Predicate<T>
等
這些都可以透過 Lambda 直接實作,讓你少打很多樣板程式碼。
範例:簡化 Enum 行為實作
在 Item 34 中提到的 Operation
Enum,如果要讓每個常數有自己的邏輯,以前只能靠覆寫抽象方法:
現在,我們可以用 Lambda 儲存行為實作:
這樣不只簡潔,還讓 enum 每個常數的行為更清晰易讀。
真實世界範例:字串過濾器
假設我們有一個商品名稱清單,想篩選出名字含有「Pro」的項目:
Lambda 在這種資料處理上非常方便,搭配 Stream API 就可以像在寫 SQL 一樣,讓邏輯更貼近需求。
劃重點:Lambda 的限制
雖然 Lambda 很方便,但也有以下限制:
- 不能處理非 Functional Interface(例如有多個抽象方法的介面)
- 沒有名稱與註解,不適合放太複雜的邏輯(建議一行為限,最多三行)
this
指的是外層類別,而非 Lambda 自己(匿名類別則不同)- 無法自我參照(無法在 Lambda 裡呼叫自身)
- 無法被序列化成跨平台傳遞的格式
若你遇到以上限制,或需要較多邏輯控制,建議還是用匿名類別或命名類別。
小結
從 Java 8 開始,使用 Lambda 是實作簡單功能邏輯的首選。它讓 Java 程式更簡潔、可讀性更高。不過要記得:
- 若邏輯超過三行、需要註解或錯誤處理,請改用方法或命名類別
- 匿名類別在一些特定情境(例如需要 self-reference 或實作多方法介面)仍有其用武之地
- Lambda 的出現,讓 Java 更接近函數式程式設計,但也需要善用其優勢與避免其陷阱