異常處理是 Java 程序健壯性的基石。理解 `Throwable` 繼承體系、`Error` vs `Exception`、`Checked` vs `Unchecked` (RuntimeException) 的區別,是編寫正確 `try-catch-finally` / `throws` 代碼的前提。
java.lang.Throwable
├── java.lang.Error // 嚴重錯誤:JVM 級、系統級,不可恢復,代碼無需捕獲
│ ├── OutOfMemoryError
│ ├── StackOverflowError
│ └── NoClassDefFoundError
└── java.lang.Exception // 程序可處理的異常
├── java.lang.RuntimeException // 運行時異常 (Unchecked):編譯器不強制捕獲
│ ├── NullPointerException
│ ├── IndexOutOfBoundsException
│ ├── IllegalArgumentException
│ └── ClassCastException
└── 其他 Exception (Checked Exception) // 編譯器強制捕獲或拋出
├── IOException
├── SQLException
├── ClassNotFoundException
└── 自定義業務異常

| 類別 | 代表 | 成因 | 處理策略 |
|---|---|---|---|
| Error | OOM, StackOverflow | JVM/硬件故障、類加載失敗 | 不捕獲,讓程序崩潰,通過監控告警、堆轉儲分析根因,優化代碼/調優 JVM 參數解決。 |
| Checked Exception (受檢異常) | IOException, SQLException | 外部資源不可控 (網絡、磁盤、DB) | 必須捕獲或聲明 throws。調用者感知風險,決定重試、降級、轉碼拋出。 |
| RuntimeException (非受檢/運行時異常) | NPE, IndexOOB, IllegalArg | 編程邏輯錯誤 (空指針、越界、參數非法) | 不強制捕獲。核心原則:預防勝於捕獲。代碼中加防御性判空、邊界檢查,讓 Bug 在測試階段暴露。 |
// 1. 捕獲具體異常,避免 catch (Exception e) 大餐
try {
FileInputStream fis = new FileInputStream("config.xml");
// ...
} catch (FileNotFoundException e) {
log.error("配置文件缺失", e);
throw new BusinessException("系統初始化失敗: 配置文件缺失", e); // 包裝轉拋
} catch (IOException e) {
log.error("讀取配置失敗", e);
throw new BusinessException("系統初始化失敗: 讀取錯誤", e);
}
// 2. finally / try-with-resources 確保資源釋放 (JDK 7+ 推薦)
try (InputStream is = new FileInputStream("data.txt")) {
// 讀取...
} // 自動調用 is.close()
// 3. 自定義異常:繼承 Exception (Checked) 或 RuntimeException (Unchecked)
public class BusinessException extends RuntimeException { // 多為 Unchecked,減少 throws 污染
private String errorCode;
public BusinessException(String msg, String code, Throwable cause) { super(msg, cause); this.errorCode = code; }
}