受检异常是编译器强制处理的Exception子类(不含RuntimeException及其子类),如IOException;非受检异常包括RuntimeException及其子类(如NullPointerException)和Error,编译时不检查。

关键看编译器是否强制你处理——必须写 try-catch 或 throws 才能通过编译的,就是受检异常;编译时完全不管、运行时才爆出来的,基本就是 RuntimeException 或其子类。
看继承关系最直接
所有异常都源自 Throwable,但路径不同:
-
受检异常:继承自
Exception,但不包括RuntimeException及其任意子类。例如IOException、SQLException、ClassNotFoundException。 -
非受检异常(Runtime 类):明确是
RuntimeException的子类,比如NullPointerException、ArrayIndexOutOfBoundsException、IllegalArgumentException。 -
注意:
Error(如OutOfMemoryError)也属于非受检,但它不是异常,而是系统级错误,通常不该也不必捕获。
看编译行为最可靠
不用背名字,动手试一试:
- 写一行可能出错的代码,比如
new FileInputStream("a.txt")—— 编译直接报错:“Unhandled exception”,说明它是受检异常。 - 再写
String s = null; s.length();—— 编译完全通过,运行才抛NullPointerException,这就是典型的非受检异常。 - 只要编译器没拦你,就不是受检异常;一旦拦住不让过,十有八九就是受检的。
看设计意图能帮判断
Java 设计这两类异常,本意很清晰:
- 受检异常对应“程序之外的问题”:文件可能被删、网络可能断、数据库连接可能失败……这些你控制不了,但可以预判、重试或友好提示,所以 Java 强制你面对。
- RuntimeException对应“程序之内的问题”:空指针、数组越界、传了非法参数……这些本该在写代码时就避免,属于 bug 范畴,不强制处理,靠测试和规范来提前发现。
常见误区提醒
有些名字带 “Exception” 却不是受检的,比如:
-
RuntimeException本身是Exception的子类,但它被 Java 特别划为非受检。 -
InterruptedException和CloneNotSupportedException看似普通,但它们是受检异常——名字不能信,得看类定义或编译反应。 - 自定义异常如果继承
Exception(没继承RuntimeException),默认就是受检的;继承RuntimeException,就是非受检的。

















