最直接区分方式是看继承关系:受检异常继承exception但不经过runtimeexception分支(如ioexception),非受检异常则向上可追溯至runtimeexception或error(如nullpointerexception、outofmemoryerror);编译器强制处理前者,对后者仅运行时抛出。

最直接的区分方式是看继承关系:只要异常类最终继承自 Exception,但**没有经过 RuntimeException 分支**,就是受检异常;只要往上追溯能碰到 RuntimeException 或 Error,就是非受检异常。
看继承链,一眼定性
编译器不靠名字判断,只认继承路径:
-
受检异常:如
IOException→Exception→Throwable,中间没经过RuntimeException -
非受检异常:如
NullPointerException→RuntimeException→Exception→Throwable;OutOfMemoryError→Error→Throwable - 自定义异常时,继承
Exception(非RuntimeException)→ 受检;继承RuntimeException→ 非受检
编译器态度是关键信号
javac 的反应是最真实的“裁判”:
- 写
new FileInputStream("a.txt")却不try-catch也不throws IOException?编译直接报错:“unreported exception IOException; must be caught or declared” - 写
String s = null; s.length();?编译完全通过,运行时才崩——这就是非受检异常的典型表现 - 哪怕你主动写
throw new IllegalArgumentException(),编译器也无动于衷
按用途和责任来理解设计意图
分类背后是 Java 对“谁该负责、能否恢复”的约定:
- 受检异常对应外部可变因素:文件可能被删、网络可能超时、数据库连接可能断。调用方有责任重试、换路径、提示用户,所以编译器强制你面对
- 非受检异常多源于内部缺陷:传了 null、数组下标越界、类型强转错误。这类问题应靠单元测试、参数校验、代码审查提前发现,而不是靠 catch 掩盖
-
Error(如
StackOverflowError)属于 JVM 层面崩溃,程序无法自救,捕获通常没有意义
常见误区提醒
这些点面试常考,也容易在实战中踩坑:
-
Exception不全是受检异常——RuntimeException是它的子类,但它本身是非受检的 -
catch (Exception e)抓不住Error,除非写catch (Throwable t)(一般不推荐) - 在 lambda 或 Stream 中抛受检异常会编译失败,因为函数式接口没声明 throws;解决办法是包装成
RuntimeException,或改用支持异常的第三方工具类 - 把本该受检的业务异常(如“库存不足”)定义成
RuntimeException子类,等于放弃语义表达,会让调用方失去响应机会
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











