Java自定义异常体系应遵循“少而准”原则,聚焦业务可读性、错误可追溯性与处理可收敛性;优先继承RuntimeException,区分校验失败、业务规则阻断、外部调用失败三类场景;每个异常需支持三种构造方式并内置errorCode等关键字段;配合@ControllerAdvice统一响应与日志;建立准入机制确保错误码唯一、命名规范、无业务逻辑。

Java 自定义异常体系不是堆砌一堆异常类,而是围绕业务可读性、错误可追溯性、处理可收敛性来设计。核心是“少而准”:只在标准异常无法准确表达业务语义时才自定义,且每个自定义异常必须承担明确职责。
明确区分受检与非受检异常的使用场景
不要为了“看起来规范”而统一用受检异常(Exception)。实际项目中,90% 以上的业务异常应继承 RuntimeException:
- 用户输入校验失败(如手机号格式错误、密码强度不足)→ 抛 IllegalArgumentException 或其子类,不强制上层处理
- 业务规则阻断(如订单已支付不可重复提交、库存不足)→ 自定义 BusinessException,含错误码和上下文信息
- 外部系统调用失败(如支付网关超时、短信平台返回 503)→ 视恢复能力决定:若重试有意义且策略由调用方控制,可用受检异常;否则用运行时异常封装后抛出
统一结构,避免信息碎片化
每个自定义异常类至少应支持三种构造方式,并内置关键字段:
- 无参构造(用于测试或简单抛出)
- 仅传 message(快速定位问题)
- 传 message + error code + cause(便于日志归因、前端展示、链路追踪)
推荐基础模板:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
立即学习“Java免费学习笔记(深入)”;
public class OrderStatusException extends RuntimeException {private final String errorCode;
public OrderStatusException(String errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public OrderStatusException(String errorCode, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}
public String getErrorCode() { return errorCode; }
}
配合全局异常处理器,实现统一响应与日志
自定义异常的价值只有在被集中捕获时才能释放。Spring Boot 项目中应搭配 @ControllerAdvice 和 @ExceptionHandler:
- 对所有 BusinessException 子类统一返回 JSON 格式:{ "code": "ORDER_LOCKED", "message": "订单已被锁定,请稍后重试", "timestamp": "..." }
- 记录 ERROR 级别日志,包含异常类名、错误码、message、traceId(如有)、关键业务ID(如 orderId)
- 对 RuntimeException 的其他子类(如空指针、类型转换失败)做兜底处理,标记为系统异常并告警
约束新增,建立准入机制
防止团队随意新增异常类导致膨胀。建议制定轻量级规范:
- 新增前先查是否已有语义接近的标准异常(如参数非法优先用 IllegalArgumentException,状态错乱优先用 IllegalStateException)
- 每个新异常类必须关联一个明确的错误码(如 USER_NOT_FOUND),且该码在全局唯一、文档可查
- 禁止出现 “XXXException” 和 “XXXEx”、“XXXExc” 等命名变体,统一后缀为 Exception
- 异常类不包含业务逻辑,不持有非 final 字段,不重写 printStackTrace()

















