Effective Java Item 49:記得檢查參數是否合法
整理 Effective Java 書中 Item 49: Check parameters for validity心得筆記
主旨
幾乎所有方法和建構子都會對輸入參數有一定的限制,例如 index 不可為負數、物件參照不可為 null 等。如果這些條件沒被滿足,我們應該要在一開始就檢查並丟出明確的例外,否則後果可能是錯誤難以追蹤,甚至導致物件狀態錯亂。
點出問題
如果不檢查參數是否合法,可能會發生下列問題:
- 方法執行到一半才炸掉,丟出難懂的例外。
- 方法「正常結束」但回傳錯誤結果。
- 更慘的是,物件進入錯誤狀態,後面程式碼才因為不相干的操作掛掉,讓人找不到問題源頭。
範例:模運算
/**
* 回傳 this mod m 的結果(保證是非負數)
* @param m 必須為正數
* @return this mod m
* @throws ArithmeticException 若 m 小於等於 0
*/
public BigInteger mod(BigInteger m) {
if (m.signum() <= 0)
throw new ArithmeticException("Modulus <= 0: " + m);
// ...進行模運算
}
這段 code 的重點在於:
- 清楚說明參數限制:m 必須為正。
- 明確定義違反限制時要丟什麼例外(ArithmeticException)。
- 一開始就檢查,避免之後出錯。
劃重點
✅ 公開方法應該怎麼做?
- 用 Javadoc 的
@throws註明例外。 - 通常使用
IllegalArgumentException、IndexOutOfBoundsException、NullPointerException等。 - 用
Objects.requireNonNull()檢查 null 值,比手動 if 判斷更簡潔。
this.strategy = Objects.requireNonNull(strategy, "strategy");
🛠 Java 9 提供的 index 檢查工具
Objects.checkFromToIndex(start, end, size);
Objects.checkIndex(index, size);
Objects.checkFromIndexSize(start, length, size);
缺點是不能自訂錯誤訊息,但用在 List/Array 索引的場景很方便。
🔒 私有或套件內部方法可以使用 assert
若你能保證呼叫方法的地方永遠不會給錯參數,那可以這樣寫:
private static void sort(long[] a, int offset, int length) {
assert a != null;
assert offset >= 0 && offset <= a.length;
assert length >= 0 && length <= a.length - offset;
// 排序邏輯
}
這些 assert 只會在開啟 -ea(enable assertions)時檢查,適合開發或測試用。
建構子一定要檢查
建構子如果沒有驗證參數,就有可能建立出狀態不合法的物件,違反類別不變式(class invariant),絕對要避免。
不要過度檢查
不是所有的檢查都值得做。若某些條件會在執行時自然導致合理例外,就不需要額外檢查。
舉例:
Collections.sort(list); // 若元素不可比較,會自然丟出 ClassCastException
如果你想強化例外訊息,也可以用「例外轉換技巧」(exception translation)來做:
try {
// 嘗試某個可能因輸入錯誤而失敗的操作
} catch (SomeException e) {
throw new IllegalArgumentException("參數不合法", e);
}
真實世界案例:
有一次曾經寫了一個方法,參數是 List<String>,但忘了檢查是否為 null。
結果 QA 在測試時發現某頁面會隨機爆 NullPointerException,log 卻完全看不出是哪裡錯。
最後花了快兩個小時才發現在某些條件下會傳 null,害整個功能崩掉。
從那之後,我就養成一定先檢查參數的習慣了。寧願一開始失敗,也不要後面出包。
小結
- 記得針對所有方法/建構子的參數做合法性檢查。
- 有條件就寫清楚、用
@throws文件化,並在程式碼中顯式檢查。 Objects.requireNonNull()是你 null 檢查的好朋友。- 私有方法用
assert,但不要在公開 API 裡依賴它。 - 建構子尤其重要,因為物件一旦建立就是你的責任。
- 失敗要早、要明確,否則會難以追蹤。
檢查參數雖然麻煩一點,但能省下很多除錯時間,是每個專業開發者都該養成的習慣。
Read other posts