| 類別 | 典型代表 | 處理原則 |
|---|---|---|
| JVM 異常 | OutOfMemoryError, StackOverflowError | 不捕獲,屬嚴重錯誤,由容器/監控處理 |
| 系統異常 | NullPointerException, IndexOutOfBoundsException, JNDI 找不到資源 | 屬 Bug 或環境故障,**單元/集成測試階段消滅**;生產環境不應出現,若出現統一拋出、記錄日志、返回通用錯誤頁 |
| 應用異常 | 驗證失敗、業務規則違反、主鍵衝突 | **可預期、可恢復**,轉換為用戶可讀信息(錯誤碼、提示文案)返回前端 |
setMonth(int m) 不應檢查 1<=m<=12,這是調用方責任;方法只保證調用後 month 正確設置且對象狀態合法。JDK 1.4 引入 assert 關鍵字,編譯需 -source 1.4,運行需 -ea 啟用。
public void setMonth(int month) {
assert month > 0 && month < 13 : \"月份非法: \" + month; // 前置條件
this.month = month;
assert invariant() : \"對象狀態不一致\"; // 後置條件/不變式
}
最佳實踐:
AssertionError(不可檢查異常),不應被捕獲處理。DataAccessException)。SQLException 等),保留原始堆棧與信息。throws 聲明傳染。try-catch,按需捕獲。將「業務邏輯拋異常」與「記錄錯誤日志」解耦:
// 業務接口
public interface ITestService { void doSomething(); }
// 實現拋出運行時異常
public class TestServiceImpl implements ITestService {
public void doSomething() { throw new RuntimeException(\"業務錯誤\"); }
}
// ThrowsAdvice 切面
public class LogAdvice implements ThrowsAdvice {
public void afterThrowing(RuntimeException ex) {
log.error(\"業務異常\", ex); // 記錄日志
// 不吞噬異常,繼續拋出保持原有流程
}
}
// Spring 配置
com.company.ITestService
throwsAdvisor
效果:業務代碼零日志代碼,切面自動織入,異常透傳不阻斷。耦合從代碼移至配置,符合關注點分離原則。
assert,外部邊界用驗證異常。