主动抛出自定义异常需先定义继承Exception或RuntimeException的异常类,再在业务规则不满足时用throw new XxxException中断执行;前者强制捕获,适用于余额不足等必须处理场景,后者用于空用户名等运行时错误。

在 Java 业务逻辑中,用 throw 主动抛出自定义异常,核心是:先定义异常类(继承 Exception 或 RuntimeException),再在需要拦截错误流程的位置用 throw new XxxException(...) 中断执行并传递上下文信息。
定义合适的自定义异常类
根据是否强制捕获来选择父类:
- 继承
Exception:编译期异常,调用方必须try-catch或throws,适合「业务可预期但必须处理」的场景(如余额不足、参数校验失败) - 继承
RuntimeException:运行时异常,调用方可不处理,适合「程序逻辑错误或非法状态」(如空用户名、非法状态转换)
建议添加带消息和原因的构造函数,并保留堆栈信息:
public class InsufficientBalanceException extends Exception {
public InsufficientBalanceException(String message) {
super(message);
}
public InsufficientBalanceException(String message, Throwable cause) {
super(message, cause);
}
}
在业务方法中用 throw 主动抛出
不要等系统出错才响应,而是在判断到非法/不满足业务规则时立即中断:
立即学习“Java免费学习笔记(深入)”;
- 检查前置条件(如用户未登录、订单已关闭)
- 验证业务规则(如转账金额 ≤ 账户余额、库存 ≥ 下单数量)
- 封装关键上下文(如订单号、用户ID、当前余额),方便日志追踪和前端提示
示例:
public void transfer(String fromAccount, String toAccount, BigDecimal amount)
throws InsufficientBalanceException {
Account account = accountService.findByAccountNo(fromAccount);
if (account == null) {
throw new InsufficientBalanceException("账户不存在: " + fromAccount);
}
if (account.getBalance().compareTo(amount) < 0) {
throw new InsufficientBalanceException(
String.format("余额不足,账户 %s 当前余额 %.2f,需 %.2f",
fromAccount, account.getBalance(), amount)
);
}
// 执行转账...
}
配合全局异常处理器统一响应
避免每个 Controller 都写 try-catch,推荐用 @ControllerAdvice 拦截自定义异常并转为标准 API 响应:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(InsufficientBalanceException.class)
public ResponseEntity<ApiResponse> handleInsufficientBalance(
InsufficientBalanceException e) {
return ResponseEntity.badRequest()
.body(ApiResponse.error(400, "交易失败", e.getMessage()));
}
}
这样业务代码专注逻辑,异常处理解耦,前端也能拿到结构化错误码和提示。
注意 throw 的使用边界
不是所有错误都该 throw 异常:
- 避免用异常控制正常流程(如用抛异常代替 if 判断)
- 不要吞掉原始异常的 cause,尤其包装第三方 SDK 错误时,用
new XxxException("msg", e)保留根因 - 敏感信息(如密码、密钥)不能出现在异常消息中,日志级别设为 DEBUG 或 TRACE 并脱敏


















