一眼判断异常是否受检:是RuntimeException子类→运行时异常;否则属Exception→受检异常。编译器强制处理受检异常因其代表外部可变场景,运行时异常则暴露代码缺陷,应修复而非掩盖。

怎么一眼判断一个异常是受检还是运行时?
看它是不是 RuntimeException 的子类:是 → 运行时异常;不是,但属于 Exception → 受检异常。比如 IOException 继承自 Exception 但没继承 RuntimeException,所以编译器会报错:“Unhandled exception type IOException”;而 NullPointerException 直接是 RuntimeException 子类,写了不处理也照常编译通过。
- 别靠名字猜:不是所有带“Exception”的都是受检异常(
IllegalArgumentException就是运行时) - IDE 提示最准:光标悬停在异常类名上,看继承树里有没有
RuntimeException - 查 Javadoc 是终极手段:点进类定义,第一行通常写着
public class XXXException extends RuntimeException或... extends Exception
为什么编译器强制处理受检异常,却放任运行时异常?
设计意图不同:受检异常代表「外部可变、程序本该应对」的场景,比如文件可能被删、网络可能断、数据库连接可能超时——这些不怪代码写得烂,但你得有兜底逻辑;运行时异常则暴露「代码本身有缺陷」,比如调用 list.get(10) 却没检查 list.size(),或对 null 对象调 .toString(),这类问题应该修复,而不是靠 try-catch 掩盖。
- 强行捕获运行时异常反而干扰调试:比如包一层
try-catch吞掉NullPointerException,结果 bug 隐藏更深 - 滥用
throws声明受检异常会污染 API:把IOException一路往上抛到main,等于放弃责任 - 真实项目中,90% 的运行时异常不该被捕获,而 80% 的受检异常必须被明确处理(哪怕只是记录日志+转成运行时异常再抛)
实际写代码时,怎么选处理方式?
核心原则:受检异常必须显式处理(try-catch 或 throws),运行时异常按需处理——只在你能恢复、能降级、或需要审计时才捕获。
- 对
FileNotFoundException:用try-catch提供默认配置,或提示用户重新选择路径 - 对
SQLException:通常包装成自定义业务异常(如OrderPersistenceException),并throws向上交由事务切面统一回滚 - 对
IllegalArgumentException:一般不捕获,而是提前校验参数,抛出时保留堆栈便于定位调用方问题 - 绝对避免:
catch (Exception e) { /* 啥也不干 */ }—— 它会同时吞掉受检和运行时异常,等于埋雷
容易忽略的关键细节
很多人以为“运行时异常不用管”,但 JVM 处理它们的方式其实很刚性:一旦抛出且未被捕获,当前线程立即终止,堆栈清空,如果发生在非主线程里,连日志都可能被吞掉。
立即学习“Java免费学习笔记(深入)”;
-
finally块在运行时异常发生时仍会执行——这是释放资源(如关闭InputStream)的最后机会 - 受检异常的声明具有传染性:A 方法
throws IOException,B 调用 A,B 就必须处理,除非 B 也throws,否则编译失败 - 自定义异常时,继承
RuntimeException还是Exception,决定了调用方是否被编译器“逼着”处理,这个决策比命名还重要






