java自定义异常应继承runtimeexception,用枚举管理错误码,提供多参数构造函数并分离context与message以保障上下文完整性和结构化日志。

Java 中自定义异常携带错误码和错误信息,关键不是把它们塞进 message 字符串里,而是用结构化字段承载语义,并通过构造逻辑确保不丢失上下文。
继承 RuntimeException,明确业务异常定位
业务异常属于流程中的合理拒绝(比如“用户未登录”“库存不足”),不是系统崩溃。因此应继承 RuntimeException,而不是 Exception:
- 避免强制调用方写 try-catch 或 throws,保持接口简洁
- Spring @Transactional 默认对 RuntimeException 回滚,便于按类型控制事务行为
- @RestControllerAdvice 默认只捕获非受检异常,统一处理才生效
用枚举统一管理错误码,禁止硬编码
错误码必须可枚举、可查、带元信息。推荐定义一个业务错误码枚举类,例如:
public enum BizErrorCode implements IErrorCode {
USER_NOT_FOUND("USER_001", "用户不存在", HttpStatus.NOT_FOUND),
INSUFFICIENT_BALANCE("PAY_003", "余额不足", HttpStatus.PAYMENT_REQUIRED);
private final String code;
private final String message;
private final int httpStatus;
// 构造 + getter 省略
}
- 每个码对应唯一业务语义,前端可直接映射提示文案
- HTTP 状态码由 Controller 层或全局处理器决定,异常类本身不耦合协议层
- 后续支持国际化时,只需替换 message 渲染逻辑,code 不变
提供多参数构造函数,保障异常链完整
至少提供三类构造方式,覆盖常见抛出场景:
- BizException(BizErrorCode code):仅传码,自动填充默认 message
- BizException(BizErrorCode code, Object... args):支持占位符动态填充,如 “订单 %s 已关闭”
- BizException(BizErrorCode code, String message, Throwable cause):包装底层异常(如 SQLException),保留原始堆栈
所有构造函数都需调用 super(message, cause),否则 getMessage() 可能为空,日志第一行就失效。
分离 context 与 message,避免字符串拼接
用户 ID、订单号、请求参数等现场信息,不应拼进 message,而应存入独立字段:
- 定义 private final Map
context ,类型需可序列化(如 HashMap) - 构造时允许传入 context,便于日志采集和问题追踪
- message 仅用于用户可见提示或开发调试,保持语义清晰、长度可控
这样既方便监控按 error_code 统计,也支持在日志中结构化输出 traceId、params 等上下文,排查效率大幅提升。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











