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

Java 異常機制全景解析:體系結構、處理流程、自定義異常與最佳實踐

     編輯:Java 相關知識

異常體系架構圖

java.lang.Throwable
├── java.lang.Error              // 嚴重錯誤,程序無法恢復 (OOM, StackOverflow)
└── java.lang.Exception          // 可處理的異常
    ├── java.lang.RuntimeException      // 非受檢異常 (Unchecked)
    │   ├── NullPointerException
    │   ├── IllegalArgumentException
    │   ├── IndexOutOfBoundsException
    │   └── ArithmeticException
    └── 受檢異常 (Checked Exception)     // 編譯期強制處理
        ├── IOException
        ├── SQLException
        ├── ClassNotFoundException
        └── 自定義業務異常

核心概念區分

維度 受檢異常 (Checked) 非受檢異常 (Unchecked/Runtime)
繼承關係 Exception 直接子類 RuntimeException 子類
編譯檢查 強制 try-catch 或 throws 編譯期不檢查
典型場景 外部資源不可控 (IO、DB、網絡) 邏輯錯誤、編程缺陷、參數非法
處理策略 預期可恢復,需顯式處理 預期不可恢復,修復代碼而非捕獲

三種異常處理方式

1. 捕獲處理 (try-catch-finally)

try {
    // 高風險代碼
    FileInputStream fis = new FileInputStream("data.txt");
} catch (FileNotFoundException e) {
    // 具體異常優先捕獲
    log.error("文件不存在", e);
    throw new BusinessException("配置文件缺失", e);
} catch (IOException e) {
    // 父類異常後捕獲
    log.error("IO錯誤", e);
} finally {
    // 必執行清理:關流、釋放鎖、關連接
    // 即使 catch 中 return/throw 也會執行
    // 唯一不執行:System.exit(0) 終止 JVM
}

2. 拋出聲明 (throws)

public void readConfig() throws IOException, SQLException {
    // 不處理,交給調用者決定
    // 調用者必須 catch 或繼續 throws
}

3. 主動拋出 (throw)

public void setAge(int age) {
    if (age < 0 || age > 150) {
        throw new IllegalArgumentException("年齡非法: " + age);
    }
    this.age = age;
}

自定義異常最佳實踐

// 業務異常基類
public class BusinessException extends RuntimeException {
    private final int code;
    private final String userMessage; // 面向用戶的友好提示
    
    public BusinessException(int code, String userMessage, String devMessage, Throwable cause) {
        super(devMessage, cause);
        this.code = code;
        this.userMessage = userMessage;
    }
    
    // 靜態工廠方法
    public static BusinessException of(int code, String userMsg, String devMsg) {
        return new BusinessException(code, userMsg, devMsg, null);
    }
}

// 具體業務異常
public class InsufficientBalanceException extends BusinessException {
    public InsufficientBalanceException(String accountId, BigDecimal balance, BigDecimal required) {
        super(400, "餘額不足", String.format("賬戶 %s 餘額 %.2f 不足支付 %.2f", accountId, balance, required), null);
    }
}

常見異常類型速查

異常 原因 類型
NullPointerException 對 null 引用調用方法/訪問字段 Runtime
ClassNotFoundException 類加載器找不到指定類 Checked
ArithmeticException 數學運算錯誤 (除零、溢出) Runtime
FileNotFoundException 文件路徑不存在/不可讀 Checked
IOException IO 操作失敗 (讀寫、關閉、網絡) Checked
SQLException 數據庫操作失敗 (SQL語法、連接、事務) Checked

黃金法則與避坑指南

  1. 異常不用於控制流程:不要用 try-catch 替代 if-else 判斷
  2. 具體異常優先捕獲:子類在前,父類在後
  3. 不吞沒異常:catch (Exception e) {} 是大忌,至少記錄日誌
  4. 保留堆棧信息:拋出新異常時帶上 cause:throw new BizEx("msg", e)
  5. finally 中不返回值:會覆蓋 try/catch 的返回/異常
  6. 資源用 try-with-resources:JDK 7+ 自動關閉實現 AutoCloseable 的資源
  7. 業務異常用 RuntimeException:減少模板代碼,由全局異常處理器統一轉換為錯誤響應
  8. 日誌記錄原則:log.error("業務描述", e) 而非 log.error(e.getMessage())

異常處理的本質是將錯誤信息從發生點傳遞到能夠處理的地方。合理設計異常體系,能讓系統在故障時快速定位、優雅降級、便於運維排查。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved