非受检异常应仅用于标识程序缺陷(如空指针、非法参数),通过自定义runtimeexception子类、统一异常策略和防御性断言提升代码可读性与健壮性,而非掩盖可恢复的业务失败。

非受检异常(Unchecked Exception)本身并不直接让代码更整洁,关键在于你如何使用它——合理利用 RuntimeException 及其子类,能减少模板式异常处理,避免无意义的 try-catch 或 throws 声明,从而让核心逻辑更聚焦、更易读。
只对“程序错误”用非受检异常
非受检异常适用于本不该发生的、反映代码缺陷的问题,比如空指针、数组越界、非法参数。这类问题靠修复代码而非捕获来解决。
- 传入 null 而方法明确要求非空?抛
IllegalArgumentException - 调用方传了负数作为索引?抛
IndexOutOfBoundsException - 对象状态不一致导致无法执行操作?自定义继承
RuntimeException的异常类,如InvalidStateException
别用非受检异常掩盖可恢复的业务失败
用户密码错误、网络超时、库存不足——这些不是 bug,而是预期中的业务分支。它们应该用受检异常(或更现代的方式,如返回结果封装、Optional、Either)显式表达,迫使调用方思考“接下来怎么办”。
- 把“用户名已存在”当作
RuntimeException抛出?调用方可能完全忽略,导致注册失败却无提示 - 用
RuntimeException包装 IO 异常再抛出?丢失了原始异常类型和上下文,不利于诊断
统一异常策略 + 明确命名 = 可读性提升
项目中约定一套非受检异常体系,比零散使用 RuntimeException 更 Clean。
- 所有校验失败统一用
ValidationException(继承 RuntimeException) - 所有领域规则冲突用
BusinessRuleViolationException - 全局异常处理器(如 Spring 的
@ControllerAdvice)集中响应这些异常,返回结构化错误信息
日志 + 断言辅助,让问题早暴露
非受检异常的价值,在于配合开发阶段的防御性检查,把问题拦在测试环境甚至 IDE 里。
- 在方法入口用
Objects.requireNonNull()或自定义断言工具快速失败 - 关键路径上记录异常前的日志,包含输入参数、上下文 ID,方便回溯
- 单元测试覆盖典型非法输入,验证是否抛出预期的非受检异常
非受检异常不是语法糖,而是设计信号:这里出错了,说明代码写错了。用得准,代码才真正简洁有力。











