Java 9中使用多个有效最终资源的try-with-resources是否存在安全性问题?
关于Java 9 try-with-resources中有效最终变量的资源关闭问题
这确实是符合Java语言规范的预期行为,但问题出在你的代码编写方式上,而非Java 9新增的有效最终变量语法本身——它并没有削弱try-with-resources的安全性,只是你需要理解它的执行逻辑和正确用法。
核心原因:资源初始化时机不在try-with-resources的管理范围内
你的代码中,Resource2 r2 = new Resource2();是在try语句执行之前就运行的,当这行代码抛出RuntimeException时,程序会直接跳转到catch块,try (r1; r2)这行代码甚至都没有被执行!
try-with-resources的自动关闭逻辑只有在try语句成功启动后才会生效:它会负责关闭所有在其资源声明列表中成功注册的资源。但在你的场景里,try语句根本没机会执行,自然不会触发任何资源的自动关闭。
正确的用法:把可能抛出异常的资源初始化放在try-with-resources声明中
如果你希望在r2初始化失败时,r1能被自动关闭,应该把r2的初始化逻辑放到try-with-resources的资源声明里,像这样:
public static void main(String[] args) { Resource1 r1 = new Resource1(); try (r1; Resource2 r2 = new Resource2()) { // r2的初始化移到这里 System.out.println("TryWithResources.main() try"); } catch (Exception e) { System.out.println("TryWithResources.main() catch"); } }
运行这段代码,你会看到输出:
TryWithResources.Resource1.close() TryWithResources.main() catch
这是因为此时try-with-resources已经开始执行,r1被成功注册为资源,即使r2初始化失败,JVM也会保证r1被自动关闭。
Java 9语法的设计意图与安全性
Java 9新增的有效最终变量支持,是为了让我们可以复用那些已经初始化完成、后续不会被修改的变量作为try-with-resources的资源,它并没有改变try-with-resources的核心安全机制:
- 只有那些被纳入try-with-resources资源列表的资源,才会在try块执行完成(无论正常结束还是异常)后被自动关闭。
- 如果资源的初始化发生在try语句之外,那么初始化阶段的异常不会触发try-with-resources的关闭逻辑——这和Java 8及以前的逻辑是一致的(比如你在Java 8中手动在finally里关闭资源,try之前的异常也不会触发finally)。
多资源场景下的安全建议
在多资源场景下使用Java 9的这个语法时,需要注意:
- 如果某个资源的初始化可能抛出异常,且希望之前的资源能被自动关闭,务必将该资源的初始化放在try-with-resources的声明中。
- 如果必须在try外面初始化资源,那么需要手动处理初始化失败时的资源关闭(比如用try-catch包裹初始化逻辑,在catch中关闭已初始化的资源)。
内容的提问来源于stack exchange,提问作者RinaldoDev
相关产品推荐
相关产品推荐

