java自定义业务异常需继承exception强制显式处理,仅在业务规则违反时由service层抛出、controller层捕获转译,并通过@controlleradvice统一处理,以区分业务与系统错误。
java中自定义业务异常(customexception)的核心是明确区分业务错误与系统错误,让异常真正承载业务语义,而不是简单包装 runtimeexception。关键不在于“能不能抛”,而在于“为什么抛、谁来处理、怎么恢复”。
一、CustomException 的标准编写方式
必须继承 Exception(非 RuntimeException),强制调用方显式处理,体现业务异常的严肃性:
- 类名以 Exception 结尾(如 OrderNotPayedException)
- 提供至少两个构造器:含 message 的构造器 + 含 message 和 cause 的构造器
- 可添加业务字段(如 errorCode、httpStatus),但避免过度设计
示例:
public class InsufficientBalanceException extends Exception {
private final String accountId;
private final BigDecimal requiredAmount;
public InsufficientBalanceException(String accountId, BigDecimal requiredAmount) {
super("账户余额不足:accountId=" + accountId + ", required=" + requiredAmount);
this.accountId = accountId;
this.requiredAmount = requiredAmount;
}
public InsufficientBalanceException(String accountId, BigDecimal requiredAmount, Throwable cause) {
super("账户余额不足:accountId=" + accountId + ", required=" + requiredAmount, cause);
this.accountId = accountId;
this.requiredAmount = requiredAmount;
}
// getter 省略
}
二、只在业务规则被违反时抛出
CustomException 不是日志替代品,也不是流程控制工具。它只用于表达合法输入下仍无法完成业务动作的场景:
- ✅ 正确:用户下单时库存为0、支付订单重复提交、会员等级不满足折扣条件
- ❌ 错误:数据库连接失败(应抛 SQLException 或 DataAccessException)、JSON 解析失败(应抛 JsonProcessingException)、NPE(应修复代码)
注意:不要用 CustomException 包裹技术异常再往上抛——那是掩盖问题根源。
三、统一在 Service 层抛出,Controller 层捕获并转译
分层职责要清晰:
- Service 方法内部检测到业务规则不满足 → 直接 new 并 throw CustomException
- Controller 捕获该异常 → 转为标准化响应(如统一 Result
结构),设置对应 HTTP 状态码(如 400 Bad Request)和业务错误码 - 避免在 DAO 层或工具类中抛 CustomException;也不要在 Controller 里 new CustomException 再 throw
这样既保障服务复用性(其他调用方也能收到明确异常),又利于前端识别错误类型做差异化提示。
四、配合全局异常处理器做收敛处理
使用 @ControllerAdvice + @ExceptionHandler 集中处理所有 CustomException 子类:
- 提取 errorCode、message、httpStatus 字段生成响应体
- 记录结构化日志(含 traceId、errorCode、关键参数),不打堆栈(业务异常无需 full stack)
- 对不同子类可定制响应逻辑(如 OrderTimeoutException 返回倒计时信息)
好处是避免每个 Controller 都写重复的 try-catch,也防止业务异常意外穿透到前端显示堆栈。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











