Throwable
├── Error // JVM 責任:動態連結失敗、虛擬機錯誤 → 應用不捕獲
└── Exception
├── RuntimeException // 程式邏輯錯誤責任:NPE、越界、非法參數 → 應用修代碼不捕獲
└── (其他) // Checked Exception:具體應用責任 → 必須聲明/捕獲/處理
核心原則:絕不向客戶端暴露 RuntimeException/Error——它們不屬於客戶解決範疇。
public class BusinessException extends ApplicationException {
public BusinessException(String msg) { super(msg); }
public BusinessException(String msg, Throwable cause) { super(msg, cause); }
}
public class ApplicationException extends Exception {
private Throwable cause;
// 構造器、initCause、getCause
// 重寫 getMessage() 遞歸拼接原因鏈訊息
// 重寫 printStackTrace() 遞歸打印 "Caused by:" 鏈
}
public void doBusiness() throws BusinessException {
try {
execute1(); // 可能拋 SQLException
execute2(); // 可能拋 IOException
}
catch (SQLException e) { throw new BusinessException("DB error", e); }
catch (IOException e) { throw new BusinessException("IO error", e); }
// 關鍵:若捕獲 Exception 必須過濾 RuntimeException!
catch (Exception e) {
if (!(e instanceof RuntimeException))
throw new BusinessException(e);
// RuntimeException 直接向上拋,不包裝
throw (RuntimeException) e;
}
}
// Struts Action 範例
public void doAction(...) {
try {
businessService.doBusiness();
}
catch (Exception e) {
if (e instanceof RuntimeException) {
// 記錄錯誤、通知開發人員、返回友好錯誤頁
log.error("Program bug!", e);
notifyDeveloper(e);
return "systemError";
}
else {
// Checked Exception (BusinessException 等) → 返回業務錯誤頁
request.setAttribute("errorMsg", e.getMessage());
return "businessError";
}
}
}
Throwable cause,initCause() 兼容 JDK 1.4+getMessage() 遞歸拼接 "msg: causeMsg: causeCauseMsg..."printStackTrace() 遞歸打印 "Caused by: ...",支援 PrintStream/PrintWriter 重載getMessage() 遇到 ApplicationException 子類停止遞歸,避免混入程式錯誤| 層級 | 職責 | 異常類型 |
|---|---|---|
| 資料存取 | 拋出具體 Checked Exception (SQLException 等) | Checked |
| 業務邏輯 | 捕獲具體 → 包裝為 BusinessException | Checked |
| 表現/控制 | 攔截 BusinessException → 用戶友好提示;攔截 RuntimeException → 記錄/告警/系統錯誤頁 | Checked / Unchecked 分流 |
| 客戶端 | 僅見業務錯誤碼/訊息,零技術細節 | — |
❌
catch (Exception e) { throw new BusinessException(e); }
→ 吞沒 RuntimeException,導致程式 Bug 偽裝成業務錯誤,開發者無感知
✅
catch (Exception e) { if (!(e instanceof RuntimeException)) throw new BusinessException(e); throw (RuntimeException)e; }
→ 分流處理,RuntimeException 保持原樣向上傳播
Exception,歸屬 Checked這套框架將「責任歸屬」內建於異常體系,讓錯誤處理從雜亂無章變為清晰可控的工程實踐。