Java 的異常機制是語言的一大特色,但許多開發者僅知 try-catch 語法,卻未深究 受檢異常 與 非受檢異常 的本質差異。本文從類繼承體系、編譯器強制要求、運行時行為、設計意圖四個維度,系統闡述兩者區別,並給出實戰選型建議。
java.lang.Exception(但不含 RuntimeException 及其子類)。如 IOException、SQLException、自定義業務異常。java.lang.RuntimeException 或 java.lang.Error。如 NullPointerException、IllegalArgumentException、ArrayIndexOutOfBoundsException。public void method1() throws CException { // 必須聲明
throw new CException("Test Exception");
}
// 調用者必須處理
try {
te.method1();
} catch (CException ce) {
// 業務恢復邏輯
}
編譯器強制調用者以 try-catch 捕獲或在方法簽名中 throws 繼續拋出,確保異常不被忽視。
public void method2(String msg) { // 無需聲明
if (msg == null) {
throw new NullPointerException("Message is null");
}
}
// 調用者可選擇性捕獲,甚至完全不處理
te.method2("Hello"); // 正常
te.method2(null); // 拋出 NPE,若不捕獲將冒泡至線程終止
編譯器不檢查,屬於「非受檢」,開發者可自行決定是否處理。
| 場景 | Checked Exception | Runtime Exception |
|---|---|---|
| 方法內拋出 | 必須 throws 聲明 | 無需聲明 |
| 調用者處理 | 強制 try-catch 或繼續 throws | 可選處理 |
| 中間方法轉發 | 必須在簽名加 throws | 可不聲明直接冒泡 |
示例:method3() 調用 method1() 但不捕獲,則必須聲明 throws CException;若調用 method2() 則無此要求。
BizException extends Exception(受檢)與 SysException extends RuntimeException(非受檢),統一錯誤碼、國際化訊息、日誌級別。SQLException 等受檢異常,轉換為業務受檢異常或系統非受檢異常再拋出,隱藏實現細節。log & rethrow,改用 Runtime Exception 減少樣板代碼。Checked Exception 與 Runtime Exception 的核心差異在於編譯器是否強制處理,這映射到異常是否屬於調用者可預期、可控制的業務範疇。合理選型,能讓異常處理成為系統健壯性的基石,而非代碼的負擔。