java.lang.Throwable
├── Error (嚴重錯誤,不可恢復,如 OutOfMemoryError、StackOverflowError)
└── Exception (異常,可捕獲處理)
├── RuntimeException (運行時異常,非受檢,編譯器不強制捕獲)
│ ├── NullPointerException
│ ├── ArrayIndexOutOfBoundsException
│ ├── IllegalArgumentException
│ └── ...
└── 受檢異常 (Checked Exception,編譯器強制捕獲或拋出)
├── IOException
├── SQLException
├── ClassNotFoundException
└── ...
try {
// 風險代碼
} catch (Exception e) {
e.printStackTrace(); // 輸出至標準錯誤流,含異常類型、訊息、完整調用棧
// 或寫入日誌框架:log.error("業務失敗", e);
}
if/else、Optional、狀態機替代。IllegalArgumentException、IllegalStateException、NullPointerException 等語義明確,減少自定義類膨脹。IOException 可重試)。try {
// 正常業務邏輯
doBusiness();
} catch (SpecificException1 e) {
// 處理特定異常1
handle1(e);
} catch (SpecificException2 e) {
// 處理特定異常2
handle2(e);
} catch (Exception e) {
// 兜底:記錄未預期異常,防止吞噬
log.error("未知錯誤", e);
throw new RuntimeException(e); // 或轉換為統一業務異常
} finally {
// 清理資源:關流、釋放鎖、歸還連接
// 必定執行(除非 JVM 退出)
closeResources();
}
try {
jdbcTemplate.query(sql);
} catch (SQLException e) {
// 包裝為業務異常,保留根因
throw new DataAccessException("查詢失敗", e);
}
JDK 1.4+ 內建支援 Throwable(initCause),printStackTrace() 會遞歸列印完整鏈路。
// 實作 AutoCloseable 的資源自動關閉,無需 finally
try (Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
return parse(rs);
} // 編譯器自動生成關閉代碼,即使拋異常也會關閉
catch (IOException | SQLException e) {
log.error("IO 或 SQL 錯誤", e);
}
// 業務異常基類(RuntimeException 系)
public class BizException extends RuntimeException {
private final String errorCode;
public BizException(String code, String msg) { super(msg); this.errorCode = code; }
public String getErrorCode() { return errorCode; }
}
// 使用
throw new BizException("USER_NOT_FOUND", "用戶不存在: " + userId);
catch (Exception e) {} 或只 log.info(e) 會掩蓋 Bug,至少 log.error + 重拋。IOUtils.closeQuietly() 或 try-with-resources。Serializable,注意 serialVersionUID。異常處理的核心哲學是「失敗快速、失敗明確、失敗安全」:讓錯誤盡早暴露(編譯期或啟動期)、異常語義清晰指向問題本質、資源在任何路徑下都能正確釋放。掌握體系結構、善用標準異常、遵循 try-with-resources 與異常鏈,即能寫出健壯、可維護的 Java 代碼。