Effective Java Item 54:回傳空集合或陣列,不要回傳 null
整理 Effective Java 書中 Item 54: Return empty collections instead of null心得筆記
主旨
當方法沒有資料可回傳時,有些人會選擇回傳 null,以代表「沒有資料」。但這麼做會讓呼叫端增加處理成本,也提高潛在錯誤發生的機率。正確做法應該是 回傳空的集合或陣列,這樣寫起來更簡潔、安全、直觀,也幾乎不會有效能損失。
點出問題:回傳 null 帶來的麻煩
先看個錯誤示範:
// ❌ 錯誤設計:回傳 null 表示沒有資料
public List<Cheese> getCheeses() {
return cheesesInStock.isEmpty() ? null : new ArrayList<>(cheesesInStock);
}
這樣會讓呼叫端寫出這樣的程式碼:
List<Cheese> cheeses = shop.getCheeses();
if (cheeses != null && cheeses.contains(Cheese.STILTON)) {
System.out.println("Jolly good, just the thing.");
}
不只冗長,而且如果忘了判斷 null,就會發生 NullPointerException。
❗ 缺點總整理:
- 呼叫端 需要額外的 null 判斷
- 忘了判斷就會出錯,錯誤可能潛藏很久
- 實作端也需要處理更多額外邏輯
- 跟 Java 的「物件導向」與「集合友善」哲學背道而馳
正確做法:回傳空集合或陣列
// ✅ 建議設計:直接回傳集合,不特別處理空資料
public List<Cheese> getCheeses() {
return new ArrayList<>(cheesesInStock);
}
甚至你可以這樣寫來進一步優化效能(避免重複建立空集合):
// ✅ 進階:重複使用 immutable 的空集合
public List<Cheese> getCheeses() {
return cheesesInStock.isEmpty()
? Collections.emptyList()
: new ArrayList<>(cheesesInStock);
}
陣列也一樣
// ✅ 正確回傳陣列,不要 null
public Cheese[] getCheeses() {
return cheesesInStock.toArray(new Cheese[0]);
}
或進一步優化:
// ✅ 進階:重複使用相同空陣列
private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0];
public Cheese[] getCheeses() {
return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY);
}
千萬不要這樣做:
// ⚠️ 誤用:預先配置陣列,效能反而更差
return cheesesInStock.toArray(new Cheese[cheesesInStock.size()]);
這種寫法反而會降低效能,應避免使用【Shipilëv 2016】。
實務建議
| 場景 | 錯誤寫法 | 正確寫法 |
|---|---|---|
| 沒資料時回傳 List | return null; | return Collections.emptyList(); |
| 沒資料時回傳陣列 | return null; | return new Type[0]; 或共享的空陣列 |
| 呼叫端 | if (list != null) | 可以直接用 for-each 迴圈或 .isEmpty() |
小結
回傳 null 是懶惰的設計方式,不只增加錯誤風險,也讓程式變複雜。
請記住:
- 回傳空集合或陣列,比回傳 null 更安全、可預測、好維護
- 可以使用
Collections.emptyList()、new T[0]或共用空陣列 - 除非測試證明效能瓶頸,否則不用過度優化
⚠️ 不要讓使用API的人去煩惱null判斷,直接回傳空集合或陣列讓他們根本不需要想!
Read other posts