Exception,編譯器強制 try-catch 或 throws。RuntimeException,編譯器不強制處理。
package custom.exception;
public class MyException extends Exception {
private static final long serialVersionUID = 1L;
// 無參建構子
public MyException() { super(); }
// 帶訊息建構子(最常用)
public MyException(String message) { super(message); }
// 帶原因建構子(支援義外鏈)
public MyException(String message, Throwable cause) { super(message, cause); }
// 僅帶原因
public MyException(Throwable cause) { super(cause); }
}
package custom.exception;
public class CheckScore {
// 宣告拋出受檢義外,強制呼叫端處理
public void check(int score) throws MyException {
if (score > 120 || score < 0) {
throw new MyException("分數不合法,必須在 0~120 之間");
}
System.out.println("分數合法:" + score);
}
}
package custom.exception;
import java.util.Scanner;
public class Student {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("請輸入分數:");
int score = sc.nextInt();
CheckScore checker = new CheckScore();
try {
checker.check(score);
} catch (MyException e) {
// 具體業務處理:記錄、轉換、友善提示
System.err.println("輸入錯誤:" + e.getMessage());
// e.printStackTrace(); // 開發期可保留堆疊追蹤
} finally {
sc.close();
}
}
}
BusinessException、ValidationException 等語意化命名,避免通用 MyException。ErrorCode 枚舉,便於前端國際化、監控告警。
public enum ErrorCode {
INVALID_SCORE(1001, "分數範圍錯誤"),
USER_NOT_FOUND(1002, "用戶不存在");
private final int code; private final String msg;
// 建構子、getter...
}
public class BizException extends RuntimeException {
private final ErrorCode errorCode;
public BizException(ErrorCode ec) { super(ec.getMsg()); this.errorCode = ec; }
}
try { jdbcTemplate.update(sql); }
catch (DataAccessException e) { throw new BizException(ErrorCode.DB_ERROR, e); }
@ControllerAdvice 統一捕獲、記錄、返回標準化錯誤響應。| 場景 | 推薦類型 | 理由 |
|---|---|---|
| 業務規則驗證失敗、可預期可恢復 | 受檢義外 | 強制呼叫端感知並處理 |
| 程式邏輯錯誤(空指標、參數非法)、不可恢復 | RuntimeException | 讓系統快速失敗,由全域處理器統一捕獲 |
| 框架/底層庫義外向上層傳遞 | 包裝為 RuntimeException | 避免汙染業務介面簽名 |
自訂義外不只是「繼承 Exception」,關鍵在於設計清晰的義外體系、豐富的錯誤上下文、統一的處理策略。良好的義外設計能大幅降低系統排錯成本,提升維護效率。