java中只有exception的子类(且非runtimeexception后代)是受检异常,必须try-catch或throws,如ioexception、sqlexception;runtimeexception及其子类(如nullpointerexception)属非受检异常,编译器不强制处理。

Java里哪些异常必须try-catch或throws?
只有Exception及其子类(但排除RuntimeException及其子类)才算受检异常,编译器强制你处理。比如IOException、SQLException、ClassNotFoundException——不显式捕获或声明抛出,代码直接编译失败。
常见错误现象:Unhandled exception type XXX 编译报错;有人硬加catch (Exception e) { }吞掉异常,结果文件读取失败却悄无声息。
- 判断依据看类继承链:是
Exception的子类?且不是RuntimeException的后代?→ 受检 -
throw new Exception()会触发检查,但throw new RuntimeException()不会 - 接口方法声明了受检异常,实现类重写时不能删掉它,也不能换成更宽泛的受检异常类型
RuntimeException到底算不算“异常”?
算,而且是异常体系里最常被抛出的一类——只是编译器不管。空指针NullPointerException、数组越界ArrayIndexOutOfBoundsException、类型转换失败ClassCastException都属于它。
使用场景:这类问题本质是程序逻辑缺陷,不是外部可变因素(如网络、磁盘)导致的。提前校验比靠catch更合理。
立即学习“Java免费学习笔记(深入)”;
- 别在业务代码里
catch (RuntimeException)来“兜底”,掩盖bug - 测试阶段故意触发
IllegalArgumentException做参数校验,比让调用方传null后崩在深处更友好 - Spring等框架抛的
DataAccessException虽继承RuntimeException,但它是抽象层封装,实际底层可能包装了受检的SQLException
为什么FileInputStream构造方法抛IOException,而ArrayList.add()不抛任何异常?
因为前者依赖外部资源(文件是否存在、权限是否足够),状态不可控,属于典型的受检异常适用场景;后者只操作内存,失败只可能是编程错误(比如并发修改),应归为RuntimeException。
参数差异直接影响异常类型选择:
- 涉及IO、网络、反射、类加载的操作,几乎都带受检异常
- 纯内存计算、集合操作、字符串处理,基本只抛
RuntimeException - 自定义异常:如果希望调用方必须意识到风险(如支付接口余额不足),就继承
Exception;如果是内部逻辑错(如状态机非法转移),继承RuntimeException
try-with-resources为什么能自动关闭,而普通try不能?
因为AutoCloseable接口定义了close()方法,JVM在字节码层面插入了隐式finally块调用它。普通try没这个契约,不关流就是资源泄漏。
容易踩的坑:
- 自己写的工具类想支持try-with-resources,必须实现
AutoCloseable,不能只写个close()方法 -
try (Resource r = new Resource())中,如果new Resource()本身抛出异常(比如构造函数里IO失败),r为null,后续不会调用close() - 多个资源用分号隔开时,关闭顺序和声明顺序相反,后声明的先关闭——这点影响不大,但要注意依赖关系(比如数据库连接要晚于Statement关闭)
受检异常机制不是为了增加负担,而是把“可能失败”的契约显性化到方法签名里。真正难的不是语法,是判断一件事该不该由调用方负责处理,还是该由当前层立刻修正或拒绝。










