应设计分层明确的异常体系:以baseexception为统一基类,下设businessexception、systemexception、externalserviceexception三个同级子类,各自按业务场景细化命名,统一携带错误码与上下文,业务异常继承runtimeexception,系统资源异常保留checked特性。

设计清晰的异常层次,核心是让每种异常类型语义明确、层级可区分、捕获有优先级。不是堆砌类,而是构建一张“错误地图”,让开发者一眼看懂错在哪一层、属于哪一类、该怎么处理。
按业务域划分顶层子类
避免所有自定义异常都直接继承 RuntimeException 或 Exception。应先定义统一基类(如 BaseException),再按业务领域派生一级子类:
- BusinessException:表示可预期的业务规则失败,比如“库存不足”“用户已存在”
- SystemException:表示系统级不稳定,如数据库连接超时、Redis不可用
- ExternalServiceException:专用于调用第三方服务失败,如支付网关返回503
这三个类互为同级,都继承 BaseException,不互相继承。这样在多 catch 中能明确区分业务逻辑问题、系统支撑问题、外部依赖问题。
同一域内按具体场景细分
在 BusinessException 下,再按模块或操作进一步细化,命名体现动词+名词结构:
- OrderValidationException(下单校验失败)
- PaymentTimeoutException(支付超时)
- InventoryLockFailedException(库存锁定失败)
它们都继承 BusinessException,但彼此不继承。这样既保留了业务异常的共性(比如统一记录审计日志、统一转 HTTP 400),又支持单独 catch 处理特定流程——例如 PaymentTimeoutException 可触发自动重试,而 OrderValidationException 直接返回前端提示。
统一携带错误码与上下文信息
每个自定义异常类不必各自重复定义 errorCode、message、userId 等字段。应在 BaseException 中统一封装:
- 构造时强制传入 ErrorCode 枚举(如 ERROR_CODE.ORDER_NOT_FOUND)
- 支持传入 Map
context,用于记录关键业务参数(如 orderId、payChannel) - 提供 getErrorCode() 和 getContext() 方法,方便全局异常处理器提取结构化数据
这样上层无需解析 message 字符串,就能准确映射状态码、生成可观测日志、驱动前端差异化提示。
严格区分检查型与非检查型异常用途
不要把 Exception 和 RuntimeException 混在同一个继承链底层:
- 所有业务异常(BusinessException 及其子类)统一继承 RuntimeException —— 调用方无需强制 try-catch,符合“业务异常应快速失败、由上层统一兜底”的实践
- 真正需要强制处理的底层资源异常(如文件读写、JDBC 连接),仍使用原始的 IOException、SQLException,或包装为新的 checked 异常(如 FileStorageException extends Exception)
- 禁止出现 BusinessException extends Exception 的设计,否则会破坏调用链的简洁性,也让多 catch 顺序变得不可靠
这种分离让编译器能帮你守住边界:该声明的必须处理,该放行的不干扰主流程。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











