选受检异常当异常可预见、外部导致且调用方需主动恢复,如文件读写失败、网络超时、业务协议强制反馈;选非受检异常当属程序逻辑错误、参数非法或状态不一致,如空参、非法id、订单状态冲突。

选受检还是非受检,关键看这个异常是不是“调用方必须知道并主动应对”的问题。
什么时候该用受检异常
当异常代表一种可预见、外部导致、且调用方有能力或责任恢复的场景时,用受检异常。编译器会强制提醒开发者处理它,避免忽略关键失败路径。
- 文件读写失败(如 FileNotFoundException)、网络连接超时、数据库操作中断——这些不是代码写错了,而是环境或资源出了问题,上层可能重试、换路径、提示用户
- 业务协议要求明确反馈(比如支付接口返回“余额不足”,需走特定补偿流程),此时抛出 InsufficientBalanceException extends Exception,让调用方无法绕过处理逻辑
- 你设计的 API 希望使用者必须考虑某种失败情形,例如解析配置时字段缺失,用受检异常能从编译期就约束契约
什么时候该用非受检异常
当异常反映的是程序逻辑错误、参数非法、状态不一致等本不该发生的内部问题时,用非受检异常(继承 RuntimeException)。它不强制捕获,但便于快速暴露缺陷。
- 参数校验失败:比如传入 null 或负数 ID,抛 IllegalArgumentException 或自定义 InvalidUserIdException extends RuntimeException
- 对象状态非法:如调用订单的“发货”方法时,订单还没支付,直接抛运行时异常,说明前置条件没满足,属于开发阶段应修复的问题
- 内部数据结构越界、空指针、类型转换错误——这类问题靠加 try-catch 没意义,应该靠单元测试和防御性编程提前拦截
自定义时的实操要点
不管哪一类,都要让异常信息清晰、可定位、可追溯。
- 继承 Exception 就是受检异常;继承 RuntimeException 就是非受检——别搞混父类
- 至少提供两个构造器:带 message 的,以及带 message + cause 的,方便封装底层异常(比如把 SQLException 包进自定义业务异常)
- 异常类名要体现语义,比如 PaymentTimeoutException(受检)、MissingRequiredFieldException(非受检),避免笼统叫 BusinessException
- 不要把所有异常都包装成受检的,否则调用方被迫写大量空 catch 或无意义 throws,反而掩盖真正需要关注的问题
不复杂但容易忽略:受检异常是契约,非受检异常是信号。用对了,代码才既健壮又干净。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











