首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 異常機制全景解析:分類、處理流程、最佳實踐與常見陷阱

     編輯:Java 程式設計入門

前言:為什麼需要異常機制?

程式運行環境複雜多變:檔案不存在、網路中斷、除數為零、記憶體耗盡……**異常機制**將「錯誤偵測」與「錯誤處理」分離,讓主流程碼保持乾淨,同時強制呼叫端面對可能的失敗情境,是構建**健壯、可維護**系統的基石。

一、異常體系繼承圖譜

java.lang.Throwable
├── java.lang.Error           // 嚴重錯誤:JVM 層面,應用無法恢復(OutOfMemoryError, StackOverflowError)
└── java.lang.Exception       // 應用層面可處理
    ├── java.lang.RuntimeException  // 非受檢異常:邏輯錯誤,編譯器不強制處理
    │   ├── NullPointerException
    │   ├── ArithmeticException
    │   ├── IndexOutOfBoundsException
    │   └── IllegalArgumentException
    └── 其他 Exception 子類別      // 受檢異常:外部環境不確定性,編譯器強制處理
        ├── IOException
        ├── SQLException
        ├── ClassNotFoundException
        └── 自訂業務異常
異常體系圖
Throwable 兩大分支:Error(不可恢復)與 Exception(可處理),Exception 再分受檢與非受檢

核心區別:受檢 vs 非受檢

維度受檢異常 (Checked)非受檢異常 (Unchecked / Runtime)
繼承自Exception (非 RuntimeException)RuntimeException
編譯器檢查✅ 強制 try-catch 或 throws❌ 不強制
典型場景I/O、資料庫、網路、反射等外部資源程式邏輯錯誤(空指標、越界、參數非法)
處理策略預期可恢復,需顯式處理屬於 Bug,應修正程式碼而非捕獲

二、三種異常處理方式

1. 捕獲處理:try-catch-finally

try {
    // 高風險操作
    FileInputStream fis = new FileInputStream("config.properties");
    // ...
} catch (FileNotFoundException e) {
    // 具體異常優先捕獲
    log.error("配置檔缺失", e);
    // 降級策略:使用預設配置
} catch (IOException e) {
    // 父類異常後捕獲
    log.error("讀取失敗", e);
} finally {
    // 無論是否拋出異常,一定執行(除非 System.exit / JVM crash)
    // 清理資源:關閉流、釋放鎖、歸還連線
}

關鍵規則:catch 區塊**由具體到一般**排序;finally 保證執行(除非 System.exit());return 在 try 中遇到 finally 會**先執行 finally 再返回**。

2. 拋出聲明:throws

// 將處理責任上傳給呼叫者
public void readConfig() throws IOException, SQLException {
    // 內部不捕獲,直接拋出
    new FileInputStream("x").close();
}

適用於:當前層級**無法妥善處理**,需由上層業務邏輯決定策略(重試、降級、回滾、向用戶提示)。

3. 主動拋出:throw

public void setAge(int age) {
    if (age < 0 || age > 150)
        throw new IllegalArgumentException("年齡必須 0~150,實際:" + age);
    this.age = age;
}

用於**防禦性程式設計**:在進入核心邏輯前驗證前置條件,失敗快速、訊息明確。

三、自訂異常:建立業務語義

// 業務異常基類
public class BusinessException extends RuntimeException {
    private final int errorCode;
    public BusinessException(int code, String msg) { super(msg); this.errorCode = code; }
    public int getErrorCode() { return errorCode; }
}

// 具體業務異常
public class InsufficientBalanceException extends BusinessException {
    public InsufficientBalanceException(String msg) { super(1001, msg); }
}

原則:業務異常通常繼承 RuntimeException(非受檢),避免汙染方法簽名;系統/資源異常繼承 Exception(受檢),強制處理。

四、finally 區塊的特殊行為

場景finally 執行?返回值影響
正常完成✅無
catch 後正常結束✅無
catch 中 return✅ 先執行 finally 再返回finally 若修改返回值/再次 return,將覆蓋原返回
try 中 return✅ 先執行 finally 再返回同上
System.exit(0)❌ JVM 直接終止不適用
JVM Crash / 死循環❌不適用

五、常見異常速查表

異常類別類型典型成因處理建議
NullPointerExceptionRuntime呼叫 null 參考的方法/欄位防禦性檢查、Optional、@NonNull 註解
ClassNotFoundExceptionChecked類路徑缺失、類名拼錯檢查依賴、打包配置
ArithmeticExceptionRuntime整數除零除前檢查分母 != 0
FileNotFoundExceptionChecked路徑錯誤、權限不足檢查路徑、權限、檔案存在性
IOExceptionCheckedI/O 失敗(磁碟滿、網路斷)重試、降級、記錄日誌
SQLExceptionCheckedSQL 語法錯、鎖超時、連線斷檢查 SQL、索引、連線池配置

六、最佳實踐十條

  1. 異常用於「異常情況」,不做流程控制(別用 try-catch 替代 if-else)。
  2. 捕獲具體異常,避免 catch (Exception e) 吞噬錯誤。
  3. 保留堆疊追蹤:throw e 或 throw new XxxException("msg", e),**絕不** throw new XxxException(e.getMessage()) 丟失堆疊。
  4. 資源在 finally 或 try-with-resources 中釋放。
  5. 自訂異常攜帶錯誤碼與上下文,便於前端/監控系統識別。
  6. 非受檢異常多為 Bug,修程式碼而非加 catch。
  7. 空指標防禦:Objects.requireNonNull()、Optional、StringUtils.isNotBlank()。
  8. 日誌記錄完整堆疊:log.error("msg", e),非 log.error(e.getMessage())。
  9. 避免在迴圈/高頻路徑拋出異常,效能極差(堆疊快照昂貴)。
  10. 文檔化 @throws:Javadoc 標註方法可能拋出的受檢異常與業務異常。

七、總結

  • 異常體系:Error(不可恢復)< Exception(可處理)→ RuntimeException(非受檢,邏輯錯)vs 其他(受檢,環境錯)。
  • 三種處理:try-catch-finally(就地處理)、throws(上傳責任)、throw(主動防禦)。
  • finally 幾乎總是執行,配合 try-with-resources 成標準資源管理模式。
  • 自訂異常建立業務語義,區分系統異常與業務異常,選擇合適繼承鏈。
  • 遵循最佳實踐,讓異常成為**診斷工具**而非**程式雜訊**。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved