会。finally块中抛异常会掩盖try或catch中的原始异常,导致原始异常被完全丢弃;Java 7+推荐用try-with-resources替代手动finally关闭,它能自动抑制次要异常。

finally 块里抛异常会掩盖原始异常吗
会。如果 try 块中已发生异常,而 finally 块又抛出新异常,原始异常会被完全丢弃,调用栈只显示 finally 中的异常——这是最常被忽略的陷阱。
- 除非显式捕获并处理,否则
finally中的throw或未捕获异常会覆盖try或catch中的异常 - 典型场景:关闭流时
close()抛IOException,但业务逻辑本已抛出NullPointerException,结果后者消失 - Java 7+ 推荐用 try-with-resources 替代手动
finally关闭,它能自动抑制(suppressed)finally类行为引发的次要异常
finally 中调用 close() 为什么有时不生效
不是“不生效”,而是可能因 close() 自身抛异常导致后续语句跳过,或资源引用为 null 未判空直接调用。
-
finally块中必须对资源对象判空:if (inputStream != null) inputStream.close(); -
close()可能抛IOException,若未捕获,会中断finally执行流,影响后续释放逻辑 - 多个资源需分别判空、分别
close(),不能链式调用(如in.close().out.close())
InputStream is = null;
try {
is = new FileInputStream("data.txt");
// ... 读取操作
} finally {
if (is != null) {
try {
is.close(); // 必须套一层 try-catch
} catch (IOException e) {
// 记录日志,不要 throw
System.err.println("Failed to close stream: " + e.getMessage());
}
}
}
try-with-resources 比 finally 更安全的三个原因
它不是语法糖,而是 JVM 层面保障资源确定性关闭的机制,解决了 finally 的固有缺陷。
- 资源声明在
try括号内,无论是否异常、是否 return,JVM 保证调用其close()方法 - 若多个资源,按声明**逆序**关闭(后声明的先关),且自动抑制非首要异常(通过
addSuppressed()) - 要求资源类型实现
AutoCloseable接口,编译期即校验,避免运行时NullPointerException
try (FileInputStream fis = new FileInputStream("a.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(fis))) {
return reader.readLine();
} // fis 和 reader 自动按 reader → fis 顺序关闭
finally 还有必要用吗?什么情况下必须手写
仍有必要,但适用场景变窄:主要用于非 AutoCloseable 资源、状态重置、日志记录等无法用 try-with-resources 表达的操作。
立即学习“Java免费学习笔记(深入)”;
- 释放 native 资源(如 JNI 分配的内存)、取消定时任务(
ScheduledFuture.cancel())、解锁ReentrantLock - 需要在异常传播前做副作用操作,例如记录耗时、标记事务回滚状态
- 与 try-with-resources **共用**是常见模式:前者管“业务级清理”,后者管“IO/连接级关闭”
别把所有清理逻辑塞进 finally;优先用 try-with-resources 处理可关闭资源,剩下的再考虑 finally —— 否则容易陷入嵌套 try/catch 和异常掩盖的泥潭。










