应定义非受检的抽象业务异常基类businessexception,统一携带错误码、上下文参数和可选cause,并按业务域分层派生accountexception、orderexception等子类,结合@controlleradvice全局处理,避免污染api签名。

统一业务异常基类的设计原则
业务异常的核心目标是让调用方清晰区分“可预期的业务失败”(如余额不足、用户不存在)和“系统级意外”(如数据库连接中断、空指针)。Java 的受检异常(Checked Exception)强制处理,但常导致模板式 try-catch 泛滥;非受检异常(RuntimeException)灵活却易被忽略。优雅解法不是二选一,而是**用一个非受检的业务异常基类承载语义,同时通过设计契约规避受检异常的侵入性**。
定义抽象业务异常基类(非受检)
所有业务异常继承自 RuntimeException,但携带结构化信息:
- 唯一错误码(String 或枚举),用于日志追踪、前端提示映射、多语言兜底
- 业务上下文参数(Object... 或 Map
),支持动态填充提示文案,避免拼接字符串 - 可选的原始异常 cause(便于链路透传底层技术异常,但不强制暴露细节给上层)
- 默认构造器私有,强制使用带错误码的构造方式,确保每个抛出点都有明确语义
示例:
public abstract class BusinessException extends RuntimeException {
private final String code;
private final Map<string object> context;
protected BusinessException(String code, String message, Map<string object> context, Throwable cause) {
super(message, cause);
this.code = Objects.requireNonNull(code);
this.context = Collections.unmodifiableMap(context != null ? context : Collections.emptyMap());
}
public String getCode() { return code; }
public Map<string object> getContext() { return context; }
}</string></string></string>
按场景分层派生具体异常类
不建议“一个 BusinessException 走天下”。应按业务域或失败类型建立轻量子类,提升可读性与可维护性:
- AccountException:账户相关(如 ACCOUNT_NOT_FOUND、INSUFFICIENT_BALANCE)
- OrderException:订单流程(如 ORDER_EXPIRED、PAYMENT_FAILED)
- AuthException:认证授权(如 TOKEN_EXPIRED、PERMISSION_DENIED)
这些子类本身不新增行为,仅作为类型标签——便于在全局异常处理器中分类响应(如返回不同 HTTP 状态码)、便于 IDE 提示、便于单元测试断言异常类型。
与 Spring 等框架协同的实践要点
在 Spring Boot 中,配合 @ControllerAdvice + @ExceptionHandler 统一处理:
- 捕获所有 BusinessException 子类,转为标准 JSON 响应(含 code、message、timestamp 等)
- 对 Throwable 或 Exception 的兜底处理仅记录 ERROR 日志并返回通用 500,避免泄露技术细节
- 关键接口方法签名不声明 throws BusinessException(不污染 API),靠文档+约定+测试保障异常语义
- 若需兼容老代码或 SDK 接口要求受检异常,可提供包装静态工厂方法:
BusinessException.toChecked()返回自定义 Checked 异常,但内部仍统一用非受检基类管理逻辑
这种设计让业务代码干净:if (user == null) throw new AccountException.NOT_FOUND(userId); —— 意图清晰,无冗余 try/catch,异常传播自然,调试时错误码直指问题根源。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











