Java中自定义带错误码的业务异常需定义枚举统一管理错误码(如INVENTORY_SHORTAGE),再继承RuntimeException封装枚举实例,支持格式化参数和HTTP状态码,实现语义清晰、可统一处理的结构化异常。

在 Java 中编写带有错误码的自定义业务异常,核心是让异常既能携带可读的业务语义(如“库存不足”),又能被系统统一识别和处理(如返回 HTTP 400 + 错误码 INVENTORY_SHORTAGE)。关键不在于“抛出异常”,而在于“结构化地表达业务失败原因”。
定义统一的错误码枚举
错误码不应散落在字符串常量或异常构造中,而应集中管理。推荐用枚举,天然支持类型安全、可遍历、易扩展:
public enum BizErrorCode {
// 格式:CODE("中文描述", HTTP状态码)
INVENTORY_SHORTAGE("库存不足", HttpStatus.BAD_REQUEST.value()),
USER_NOT_FOUND("用户不存在", HttpStatus.NOT_FOUND.value()),
ORDER_EXPIRED("订单已过期", HttpStatus.GONE.value()),
PARAM_INVALID("参数校验失败", HttpStatus.BAD_REQUEST.value());
<pre class="brush:php;toolbar:false;">private final String message;
private final int httpStatus;
BizErrorCode(String message, int httpStatus) {
this.message = message;
this.httpStatus = httpStatus;
}
public String getMessage() { return message; }
public int getHttpStatus() { return httpStatus; }
}
这样做的好处:调用方无需硬编码字符串;前端/日志可通过 code.name() 获取机器可读码,code.getMessage() 获取用户提示;后续加监控、国际化也更方便。
编写带错误码的自定义异常类
继承 RuntimeException(非检查异常,符合 Spring 等主流框架习惯),并持有错误码枚举实例:
public class BizException extends RuntimeException {
private final BizErrorCode errorCode;
<pre class="brush:php;toolbar:false;">// 构造:只传错误码(最常用)
public BizException(BizErrorCode errorCode) {
super(errorCode.getMessage());
this.errorCode = errorCode;
}
// 构造:错误码 + 额外上下文信息(如订单号)
public BizException(BizErrorCode errorCode, Object... args) {
super(String.format(errorCode.getMessage(), args));
this.errorCode = errorCode;
}
// 提供获取错误码的方法
public BizErrorCode getErrorCode() {
return errorCode;
}
// 可选:返回 HTTP 状态码,便于全局异常处理器直接使用
public int getHttpStatus() {
return errorCode.getHttpStatus();
}
}
注意:
- 不重写 getMessage(),避免干扰日志和调试;
- 支持格式化参数(如 new BizException(USER_NOT_FOUND, "U12345") → “用户不存在” → 实际提示“用户 U12345 不存在”);
- 异常本身不负责日志打印,由统一异常处理器决定是否记录。
在业务代码中使用
直接抛出,语义清晰,无需 if-else 套 try-catch:
- 库存校验失败时:
if (stock - 查不到用户时:
if (user == null) throw new BizException(USER_NOT_FOUND, userId); - 参数不合法时:
if (!isValid(phone)) throw new BizException(PARAM_INVALID, "手机号");
这种写法把“错误是什么”和“怎么处理它”解耦了——业务方法只关注“该不该失败”,不关心“失败后返回什么 JSON”。
配合全局异常处理器统一响应
用 @ControllerAdvice 捕获 BizException,输出标准格式:
@RestControllerAdvice
public class GlobalExceptionHandler {
<pre class="brush:php;toolbar:false;">@ExceptionHandler(BizException.class)
public ResponseEntity<apiresponse> handleBizException(BizException e) {
ApiResponse response = ApiResponse.fail(
e.getErrorCode().name(), // 错误码(如 "INVENTORY_SHORTAGE")
e.getMessage(), // 用户提示(如 "库存不足")
null // 可选:附加数据,如 {"itemId": 1001}
);
return ResponseEntity.status(e.getHttpStatus()).body(response);
}</apiresponse>
}
其中 ApiResponse 是你定义的统一响应体(含 code、message、data 字段)。这样所有业务异常都走同一出口,前端无需判断多种 error 字段,后端新增错误码也不用改控制器。
不复杂但容易忽略:错误码要命名规范(大写+下划线)、枚举值不可变、异常类保持轻量、全局处理器别吞掉原始堆栈(调试时需要)。做好这几点,业务异常就真正成了系统间沟通的“标准协议”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











