異常處理是 Java 健壯性的基石。本文系統梳理異常體系、處理流程、自定義異常、try-with-resources 等核心機制,並總結生產環境常見錯誤模式。
java.lang.Throwable
├── Error // 嚴重錯誤,不可恢復(OOM, StackOverflow)
└── Exception // 可處理的異常
├── RuntimeException // 非檢查異常(空指針、越界、類轉換)
└── 其他 // 檢查異常(IO、SQL、ClassNotFound)
throw:顯式拋出異常對象throws:方法簽名聲明拋出檢查異常try-catch-finally:捕獲並處理,finally 保證資源釋放try {
// 高風險代碼
} catch (SQLException | IOException e) { // Java 7+ 多重捕獲
log.error("資源訪問失敗", e);
throw new BusinessException("數據層異常", e); // 保留原始堆棧
} finally {
closeResources(); // 必執行清理
}
// 自動關閉實現 AutoCloseable 的資源
try (Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
return ps.executeQuery();
} // 編譯器自動生成 finally 關閉邏輯
| 維度 | 檢查異常 | 非檢查異常 |
|---|---|---|
| 編譯器強制 | 是(必須 catch 或 throws) | 否 |
| 典型場景 | 外部依賴失敗(IO、網絡、數據庫) | 編程錯誤(參數非法、邏輯缺陷) |
| 恢復可能性 | 高(可重試、降級、轉碼) | 低(通常需修復代碼) |
| API 設計建議 | 調用方必須感知並處理的情況 | 調用方無法合理處理的情況 |
// 業務異常基類:非檢查,攜帶錯誤碼
public class BizException extends RuntimeException {
private final int code;
public BizException(int code, String msg) { super(msg); this.code = code; }
public BizException(int code, String msg, Throwable cause) { super(msg, cause); this.code = code; }
}
// 使用示例
if (user == null) throw new BizException(4001, "用戶不存在");
if (balance < amount) throw new BizException(4002, "餘額不足");
catch (Exception e) {} → 至少記錄日誌或重拋catch (Exception e) 捕獲過廣 → 精確捕獲具體異常throw new MyException() 未帶 cause → 永遠保留鏈路Thread.currentThread().interrupt()throws 傳遞契約信息AutoCloseable + try-with-resources 成標配