java自定义异常需继承exception或runtimeexception,明确检查型与非检查型语义,提供message、cause等构造方法,可添加final业务字段并封装getter,抛出时应直接使用或包装底层异常以保留堆栈。

Java 中自定义异常的核心是继承 Exception 或 RuntimeException,并提供有意义的构造方法,让调用方能清晰理解错误语义、方便排查和处理。
明确异常类型:检查型 vs 非检查型
选择继承哪个父类,决定了是否强制要求调用方处理:
- 继承 Exception(如
MyBusinessException extends Exception)→ 编译期检查异常,调用处必须try-catch或声明throws - 继承 RuntimeException(如
InvalidOrderStateException extends RuntimeException)→ 运行时异常,不强制捕获,适合程序逻辑错误或不可恢复的非法状态
原则:业务规则违反(如余额不足、参数非法)通常用运行时异常;外部依赖失败(如数据库连接超时、文件不存在)可考虑检查型异常,但现代实践中也倾向统一用运行时异常简化调用方负担。
提供实用的构造方法
至少覆盖三种常见使用场景:
-
MyException(String message)—— 带提示信息 -
MyException(String message, Throwable cause)—— 带原始异常堆栈(用于包装底层异常) -
MyException(Throwable cause)—— 简洁封装(message 可自动取自 cause)
示例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
public class InsufficientBalanceException extends RuntimeException {
public InsufficientBalanceException(String message) {
super(message);
}
public InsufficientBalanceException(String message, Throwable cause) {
super(message, cause);
}
public InsufficientBalanceException(Throwable cause) {
super(cause);
}
}
添加业务字段(按需)
如果异常需要携带上下文数据(如订单号、用户ID、错误码),可在类中定义 final 字段,并在构造中初始化:
- 避免在异常中放可变对象(如 List、Map),防止被意外修改
- 提供 getter 方法供上层提取关键信息,便于日志记录或前端返回
示例:
public class OrderValidationException extends RuntimeException {
private final String orderId;
private final int errorCode;
public OrderValidationException(String orderId, int errorCode, String message) {
super(message);
this.orderId = orderId;
this.errorCode = errorCode;
}
public String getOrderId() { return orderId; }
public int getErrorCode() { return errorCode; }
}
抛出与包装的合理方式
抛出自定义异常不是简单 new + throw,要注意语义准确和链路完整:
- 直接抛出:校验失败、业务约束不满足时,直接 new 并 throw
- 包装抛出:捕获底层异常(如 SQLException、HttpClientException)后,用自定义异常包裹再抛出,保留原始堆栈
- 避免裸 throw new Exception("xxx"),也不要用通用异常替代业务异常
示例包装场景:
try {
paymentService.charge(orderId, amount);
} catch (PaymentFailureException e) {
throw new BusinessPaymentException("支付调用失败", e); // 包装
}
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










