java自定义异常需将错误码固化为实例属性,通过构造函数赋值并提供getter方法;统一继承baseexception基类,全局处理器拦截;采用六位数字错误码格式(如201001),支持模块划分与聚合;异常类需支持上下文透传和异常链。

Java 自定义异常带错误码,核心是让错误码成为异常对象的固有属性,而不是靠反射、枚举静态值或外部映射来临时获取。这样日志可读、接口响应结构化、前端能直接消费,排查和扩展也更可靠。
错误码必须固化在异常实例上
别只传一个 ErrorCode 枚举进去就完事。如果没把 code() 和 message() 显式赋值给异常字段,日志里只能看到类名,前端收到的响应还得额外解析——这违背了异常“自解释”的设计初衷。
-
构造函数中调用
errorCode.code()和errorCode.message(),传给super(message),同时存为this.errorCode和this.errorMessage - 提供
getErrorCode()、getErrorMessage()方法,全局处理器可直取,不依赖类型判断或反射 - 避免在
@ExceptionHandler里再查一遍枚举,否则容易空指针,也重复耦合逻辑
统一继承抽象基类,别用 instanceof 分发
写一堆 if (e instanceof XxxException) 的处理器,新增异常就得改代码,还容易误捕子类(比如 PaymentException extends BusinessException)。
- 所有业务异常继承同一个抽象基类(如
BaseException),该类声明getErrorCode()、getErrorLevel()等通用方法 - 全局处理器用
@ExceptionHandler(BaseException.class)拦住全部业务异常,用@ExceptionHandler(Throwable.class)拦未预期异常 - HTTP 状态码由 Controller 层或处理器统一映射,不要塞进错误码枚举里(协议层和业务层要解耦)
错误码格式要支持模块划分和机器识别
纯数字(如 1001)难定位归属模块;纯字符串(如 "USER_NOT_FOUND")无法做范围判断和聚合统计。
- 推荐六位数字格式,例如
201001:前两位表示项目(20)、中间两位表示模块(10)、后两位表示序号(01) - 用枚举实现时,每个项应提供
projectCode()、moduleCode()、errorCode()三个方法,便于监控和告警按模块聚合 - 上线后错误码语义不可变更;废弃需明确标注,新增走新码
异常类要支持上下文透传和异常链
光有错误码和提示不够,真实排障常需订单 ID、用户 ID、时间戳等上下文信息。同时,底层异常(如 SQL 异常)的堆栈不能丢。
- 提供多构造函数:
BizException(String message)、BizException(String message, Throwable cause)、BizException(ErrorCode code, String message, Map<string object> context)</string> - 内置不可变
context字段(如Map<string object></string>),用于透传关键排障字段,不污染getMessage() - 日志打印时,统一模板包含
errorCode、message、context和完整堆栈,不拼接敏感信息(如 token、密码)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











