非受检异常默认不强制捕获但会立即中断执行路径,栈向上退出直至被捕获或线程终止;其本质是代码缺陷信号,应优先通过参数校验、状态检查、optional 等前置防御修复,而非依赖捕获兜底。

非受检异常(如 NullPointerException、IllegalArgumentException、ArrayIndexOutOfBoundsException)默认不强制捕获,但一旦抛出,会立即中断当前执行路径——除非被显式 try-catch 拦截。这种中断不是“暂停”,而是栈向上逐层退出,直到遇到匹配的 catch 块或线程终止。
非受检异常天然中断业务流程
它不依赖编译器检查,但运行时行为明确:方法中抛出非受检异常后,该方法后续语句不再执行,调用方若未捕获,异常继续上抛,整个调用链同步中断。例如:
- 用户注册方法中校验邮箱格式失败,抛出
IllegalArgumentException→ 注册逻辑立刻停止,不会继续写库或发邮件 - 订单结算时访问空支付对象的
getId()→ 触发NullPointerException→ 结算事务回滚前就已退出,需靠外层统一异常处理兜底
捕获非受检异常的合理场景
不是所有非受检异常都该被 catch,只有满足以下条件时才建议拦截并恢复流程:
- 异常可明确归因于外部输入(如 API 参数、配置值),且业务允许降级或默认值替代
- 属于已知的、可控的边界情况(如第三方 SDK 文档明确说明某方法可能抛
IllegalStateException) - 需要记录上下文日志、触发监控告警,但不改变主流程语义(比如记录失败但返回空结果)
反例:在循环中捕获 NullPointerException 却不修复空指针来源,只是吞掉异常继续跑——这掩盖缺陷,不是容错。
避免用捕获代替修复
非受检异常本质是代码缺陷信号。与其层层 try-catch,不如前置防御:
- 参数校验:方法入口用
Objects.requireNonNull()或StringUtils.isNotBlank()快速失败 - 状态检查:调用前确认对象是否处于可用状态(如
if (httpClient.isClosed()) throw new IllegalStateException(...)) - 使用 Optional:对可能为空的返回值建模,迫使调用方显式处理空分支
捕获只是兜底手段,修复才是根本解法。
与业务异常分层的配合
真实系统中,应区分两类“异常”:
- 非受检异常:代表程序 bug 或不可预期状态,应快速暴露、定位、修复
- 自定义业务异常(继承 RuntimeException):代表合法的业务拒绝(如“余额不足”“库存已售罄”),它们是流程的一部分,应被上层捕获并转化为用户友好的提示或补偿动作
二者共存时,建议用全局异常处理器(如 Spring 的 @ControllerAdvice)分别响应:对前者记录错误日志并返回 500;对后者返回 200 + 业务码和消息。










