異常處理非單純 try-catch,而是關於責任劃分:誰拋出?誰捕獲?誰恢復?誰記錄?本文系統梳理七種典型處理模式、三大經典錯誤,並提煉四條黃金法則。
public void methodA() {
try { methodB(); }
catch (ExceptionType e) { /* 統一處理:記錄、轉換、用戶提示 */ }
}
public void methodB() throws ExceptionType {
if (condition) { /* 正常邏輯 */ }
else { throw new ExceptionType("業務規則違反"); }
}
機制:JVM 沿調用棧向上尋找匹配的 catch。適用於「底層檢測錯誤、上層決策處理」的分層架構。
public void methodA() {
try { /* 可能出錯操作 */ }
catch (ExceptionType e) { /* 就地處理:重試、預設值、降級 */ }
}
適用:錯誤可在本方法上下文完全解決,無需外部感知。
public void methodB() throws ExceptionType {
try { /* 可能出錯 */ }
catch (AnotherException e) { /* 處理 AnotherException,不拋出 */ }
// ExceptionType 未捕獲 → 自動拋給調用者
}
關鍵:方法簽名 throws ExceptionType 僅聲明未被捕獲的異常類型。
public void methodB() throws ExceptionType {
Resource res = acquire();
try { /* 使用資源 */ }
finally { res.release(); } // 異常拋出前保證執行
}
語義:finally 區塊總會執行(除 JVM 崩潰),用於資源清理,非業務異常處理。
public void methodB() throws ExceptionType {
try { ... }
catch (ExceptionType e) { /* 處理了 */ } // 吞掉異常,外層永遠收不到
}
後果:throws 失效,調用者以為需處理實際不需,破壞契約誠信。
public int methodB() {
try { return 1; }
finally { return 2; } // 真實返回值永遠是 2!
}
鐵律:finally 中的 return/throw 會覆蓋 try/catch 的返回/拋出。嚴禁在 finally 中使用 return/throw。
try { ... }
catch (Exception e) { ... } // 捕獲所有 Exception 及子類
catch (SQLException se) { ... } // 永遠執行不到!
修正:catch 區塊由具體到通用排序,Exception 必須置於最後作為安全網。
throw new BizException(e)),保留堆疊追蹤throws 交給調用者,切勿吞沒catch (IOException | SQLException e) 合併處理同邏輯異常,避免重複代碼優秀的異常處理,是將「系統異常狀態」轉化為「可決策的業務訊息」。記住:Catch 是決策點,Finally 是承諾,Throw 是移交責任。在每個層級問自己:「我在這裡能做什麼有意義的事?」答案即指引代碼結構。