Effective Java Item 45:謹慎使用 streams
整理 Effective Java 書中 Item 45: Use streams judiciously 心得筆記
主旨
Java 8 推出的 streams API 是用來處理「大量資料的處理流程」的工具,它支援類似函式式的操作(例如 map、filter、collect 等),並能以流暢的語法串接多個處理階段。然而,streams 是一把雙面刃:用得好能讓程式簡潔清楚,用不好會讓人看不懂又難維護。
本篇要講的重點就是:該用的時候再用,避免過度使用。
點出問題
stream pipeline 可以寫得很精簡,例如:
但你也可以寫得非常複雜到沒人看得懂:
這段看似高端,但實際上維護困難,debug 也困難。
範例:Anagrams 程式三種寫法
傳統 for-loop 寫法(可讀性高)
搭配後續處理與顯示的部分即可達成需求,清楚、易懂、方便除錯。
過度使用 streams 的寫法(不建議)
這段一次完成整個處理流程,但太複雜,別人幾乎看不懂,自己三週後也會忘記在寫什麼。
折衷、清晰版本(建議)
這樣寫保留 streams 的優點,同時兼顧可讀性。
劃重點
哪些場景適合用 streams?
- 要處理資料轉換(map)
- 篩選資料(filter)
- 統計運算(count, sum, average)
- 資料分組(groupingBy)
- 查找符合條件的元素(findFirst, anyMatch)
哪些情況避免使用?
- 需要操作多個中間結果的對照資料(streams 一經 map 就無法回頭)
- 需要 break/continue 或 return 外層方法(lambda 無法做到)
- 涉及錯誤處理與多種異常(checked exception 不好處理)
- 要處理 char[] 時(Java streams 對 char 支援不友善)
真實世界範例:過濾出有效 email 清單
假設你有一串使用者輸入的 email 清單,裡面可能包含空字串或格式錯誤的 email。我們可以用 stream 簡單過濾出有效項目:
這樣寫簡潔而具表達力,但若要在中間處理 p 本身的值,就必須用 pair 或其他 workaround,程式會變複雜。
小結
使用 streams 的指導原則:
- ✔️ 當你需要表達「資料轉換流程」時,用 streams。
- ✔️ 當處理簡潔、單純的資料流轉流程時,用 streams。
- ❌ 當你需要 break、回傳、修改區域變數或處理錯誤時,避開 streams。
- ❌ 當你發現自己寫了兩層以上的 lambda,停下來想一下是否要改寫。
最後提醒,streams 是輔助,不是萬能。在團隊協作中,寫出大家看得懂的程式碼比用最炫的語法還重要。
Read other posts