受检异常的核心价值是强制调用方处理可恢复的业务异常,要求消息具体到业务上下文、保留异常链、对外脱敏并统一响应结构,且不包含修复指南。

受检异常(Checked Exception)的核心价值在于强制调用方感知并处理可恢复的业务异常。它不是用来标记程序错误,而是为那些“本可以继续执行,但需要上层介入决策”的场景服务。因此,异常信息的设计与传递必须服务于这个目标:清晰、准确、可操作。
异常消息要具体到业务上下文
避免泛泛而谈的“操作失败”“系统异常”,消息应明确指出什么错了、在哪错的、为什么错。这能减少排查成本,也便于前端或日志系统做语义化处理。
- ❌ 不推荐:
"注册失败"、"数据异常" - ✅ 推荐:
"用户名 'admin' 已被占用,请更换"、"订单ID order-20260611001 库存不足,当前可用量为0" - 说明:消息中包含关键业务标识(如用户名、订单ID)、具体状态(已占用、可用量为0),让接收方无需查日志就能理解问题本质
异常链(cause)必须保留原始根源
当在业务层包装底层异常(如将 SQLException 封装为 UserRegisterException)时,务必通过带 cause 的构造器传递原始异常。这既保留了堆栈完整性,又实现了层次解耦。
- 正确做法:
throw new UsernameExistsException("用户名重复", originalSQLException); - 错误做法:仅用字符串拼接掩盖原始异常,或忽略 cause 参数
- 效果:日志中可追溯完整调用链;调试时能快速定位是 SQL 执行问题还是校验逻辑问题
对外暴露时需脱敏并统一结构
受检异常本身不应直接透传给前端或外部系统。应在统一异常处理器(如 @ControllerAdvice)中拦截,提取关键字段,转为标准化错误响应体。
- 响应体建议包含:
code(业务错误码,非HTTP状态码)、message(用户友好的提示)、requestId(用于日志追踪) - 敏感信息(如数据库表名、路径、堆栈)一律过滤,不进入响应正文
- 示例:{"code":"USER_NAME_CONFLICT","message":"该用户名已被注册","requestId":"req-8a9b3c"}
不要在异常消息里写修复指南或技术建议
异常消息面向的是调用方(可能是另一个服务或前端),不是开发者。指导性内容(如“请检查网络连接”“重启应用重试”)应放在文档或监控告警中,而非异常构造时硬编码。
- ❌ 避免:
"数据库连接超时,请检查JDBC配置并重试" - ✅ 合理:
"用户数据保存失败:数据库操作超时",由统一日志记录完整堆栈供运维分析 - 理由:异常是信号,不是说明书;过度指导会污染业务语义,且容易过时











