// 糟糕:用 ArrayIndexOutOfBoundsException 結束迴圈
try {
int i = 0;
while (true) range[i++].climb();
} catch (ArrayIndexOutOfBoundsException e) {
// 視為正常結束,什麼都不做
}
for (Mountain m : range) m.climb();
climb() 內部也拋出相同異常,會被外層捕獲吞噬,導致真實錯誤隱形提供狀態檢查方法 (hasNext()、hasMoreElements()) 讓客戶端避免異常控制流:
// Iterator 設計:狀態檢查 + 取值分離
for (Iterator i = c.iterator(); i.hasNext(); ) {
Foo f = i.next(); // 無異常風險
}
| 類別 | 適用場景 | 範例 | 處理義務 |
|---|---|---|---|
| 受檢異常 | 呼叫端可合理恢復 | 餘額不足、檔案不存在、網路超時 | 強制 catch 或 throws 傳播 |
| 執行時異常 | 程式邏輯錯誤 (Bug) | 空指標、陣列越界、非法參數 | 無義務捕獲,修正代碼而非處理 |
| Error | JVM/資源嚴重故障 | OOM、StackOverflow、類別載入失敗 | 通常不捕獲,讓程式崩潰 |
public class InsufficientFundsException extends Exception {
private final double balance;
private final double required;
public InsufficientFundsException(double balance, double required) {
super(String.format("餘額 %.2f 不足支付 %.2f", balance, required));
this.balance = balance; this.required = required;
}
public double getBalance() { return balance; }
public double getShortfall() { return required - balance; }
}
呼叫端可捕獲後讀取具體數值決定重試/提示/轉帳等恢復策略。
// 僅 log 或 exit,無實質恢復
try { doSomething(); }
catch (TheCheckedException e) {
e.printStackTrace(); System.exit(1);
}
// 或直接轉為 AssertionError
try { doSomething(); }
catch (TheCheckedException e) { throw new AssertionError(); }
此類情況改用 未受檢異常 更誠實、更簡潔。
| 標準異常 | 適用場景 |
|---|---|
IllegalArgumentException | 參數值不合法 (非 null) |
IllegalStateException | 物件狀態不適合該操作 (如未初始化就調用) |
NullPointerException | 禁止 null 卻傳入 null |
IndexOutOfBoundsException | 索引參數越界 |
ConcurrentModificationException | 禁止並發修改時檢測到修改 |
UnsupportedOperationException | 物件不支援該操作 (如唯讀集合 add) |
優勢:復用代碼、API 易學、可讀性高、工具鏈支援完善。
// 糟糕:SQLException 直接拋出至 Service 層
public User findById(long id) throws SQLException { ... }
try {
return jdbcTemplate.queryForObject(sql, mapper, id);
} catch (DataAccessException e) {
throw new UserNotFoundException("用戶不存在: " + id, e); // 根因包裝
}
UserNotFoundException)getCause() 保留完整堆疊追蹤,除錯無損拋出異常時封裝關鍵上下文:
throw new IndexOutOfBoundsException(
String.format("索引 %d 超出範圍 [0, %d)", index, size)
);
// 或自訂異常提供 getter
throw new InsufficientFundsException(balance, amount);
堆疊追蹤 + 詳細訊息 = 秒級定位問題。
失敗後物件保持可用狀態 (調用前狀態):
public Object pop() {
if (size == 0) throw new EmptyStackException(); // 狀態未變
Object result = elements[--size];
elements[size] = null;
return result;
}
注意:併發修改下難以保證,需鎖/不可變/無鎖資料結構配合。
// 糟糕:空 catch 吞噬異常
try { dosomething(); } catch (SomeException e) { }
// 可接受:關閉資源時忽略 (資料已讀完)
try { inputStream.close(); } catch (IOException e) { log.debug("關閉流失敗", e); }
// 原則:至少記錄日誌,否則 Bug 會在未來爆發