在 Java 異常體系中,RuntimeException 佔有特殊地位。它是所有「未檢查異常」的父類別,代表程式邏輯錯誤而非外部環境問題。本文將剖析 RuntimeException 的運作機制、為何編譯器不強制捕獲、未捕獲時的行為,以及開發時的應用原則。
RuntimeException 及其子類別(如 NullPointerException、ArrayIndexOutOfBoundsException、IllegalArgumentException)統稱為未檢查異常。它們的共同特徵是:
throws 宣告,也不強制呼叫端以 try-catch 處理若每個可能產生 NullPointerException 的呼叫都需檢查並捕獲,程式碼將充斥著防禦性 if (obj != null),嚴重降低可讀性。Java 設計者認為:
當 RuntimeException 一路冒泡到 main() 仍未被捕獲,JVM 會呼叫 ThreadGroup.uncaughtException(),預設行為是印出完整堆疊追蹤至標準錯誤輸出:
public class NeverCaught {
static void f() { throw new RuntimeException("From f()"); }
static void g() { f(); }
public static void main(String[] args) { g(); }
}
輸出:
java.lang.RuntimeException: From f()
at NeverCaught.f(NeverCaught.java:9)
at NeverCaught.g(NeverCaught.java:12)
at NeverCaught.main(NeverCaught.java:15)
雖多為 JVM 自動拋出,但在下列情境開發者可主動拋出:
if (arg < 0) throw new IllegalArgumentException("參數不可為負");IllegalStateExceptionUnsupportedOperationException一般原則:不要捕獲 RuntimeException 或其父類別 Exception 來「吞沒」錯誤。但有例外:
即使捕獲,也應重新拋出或包裝為檢查型異常,避免錯誤無聲無息被忽略。
| 特性 | RuntimeException (未檢查) | 一般 Exception (已檢查) |
|---|---|---|
| 代表意義 | 程式邏輯錯誤 | 外部環境/可預期錯誤 |
| 編譯器強制 | 否 | 是 |
| 典型範例 | NPE, 陣列越界, 參數非法 | IOException, SQLException |
| 處理策略 | 修正程式碼避免發生 | try-catch 處理或向上拋出 |
理解 RuntimeException 的設計哲學,能幫助你在異常處理上做出更合理的架構決策:檢查型異常用於「預期內的失敗」,執行期異常用於「預期外的錯誤」。