異常處理是 Java 開發者日常必面對的課題,但許多人缺乏系統性原則:遇到受檢異常就胡亂 try-catch 加 printStackTrace(),運行時異常則直接忽略。這種做法除除錯略有幫助外,實務上毫無價值。本文從 Java 異常體系入手,針對 J2EE 典型四層架構 (DAO、業務、控制、展示) 提出具體處理準則。
Throwable (受檢)
├── Error (非受檢) - 嚴重系統錯誤,應用不應捕獲
├── Exception (受檢) - 應用層級異常
│ └── RuntimeException (非受檢) - 程式邏輯錯誤 (NullPointer, IllegalArgument...)
Exception 及其子類 (排除 RuntimeException),編譯器強制處理RuntimeException 及其子類,編譯器不強制Throwable/Error 通常用於基礎框架層,業務代碼少見場景: 使用原生 JDBC 無法避免 SQLException;若用 Spring JDBC Template 則無受檢異常拋出,代碼更優雅。
原則: 捕獲底層異常 (如 SQLException),包裝拋出自訂非受檢異常 (繼承 RuntimeException)。
優勢:
throws SQLException,日後換用 Spring/ORM 介面無需變動粒度建議: 模組級別定義一個 DAO 運行時異常 (如 ModuleXxxDAORuntimeException),而非每個 DAO 方法/類別各定義一個。過度細粒度導致 Service 層捕獲大量異常類別,代碼混亂難維護。
// 推薦做法
throw new OrderDAORuntimeException("查詢訂單失敗", sqlException);
// 避免:為每個 DAO 定義獨立異常類別
核心原則: Service 方法代表一個完整業務單元,應包含完整交易邊界。避免「Controller 調用多個 Service 完成一業務」的反模式 (交易應在 Service 層管理)。
處理策略:
XxxServiceRuntimeException 捕獲不可避免的底層異常轉譯拋出口訣: 「盡可能不讓異常污染 Service 介面!」
主流 MVC 框架 (Struts2、Spring MVC) 已內建異常攔截機制,控制層通常聲明 throws Exception 由框架統一處理。開發者僅需關注:
處理方式依需求彈性選擇:
new MyException(msg, cause))以上觀點僅代表個人實務經驗,歡迎交流探討。
出處:https://lavasoft.blog.51cto.com/62575/244138