声明多个有效的最终资源时,try-with-resource 是否不安全?

问题描述 投票:0回答:2

从 Java 9 开始,我们可以在 try-with-resources 中有效地使用最终变量。 (参见JEP 213。)

下面的示例展示了一种情况,其中一个资源初始化抛出异常。

    public static void main(String[] args) {
        Resource1 r1 = new Resource1();
        Resource2 r2 = new Resource2(); // exception will be thrown
        try (r1; r2) {
            System.out.println("TryWithResources.main() try");
        } catch (Exception e) {
            System.out.println("TryWithResources.main() catch");
        }
    }
    
    static class Resource1 implements AutoCloseable {
        @Override
        public void close() throws Exception {
            System.out.println("TryWithResources.Resource1.close()");
        }
    }
    
    static class Resource2 implements AutoCloseable {
        public Resource2() {
            throw new RuntimeException();
        }
        @Override
        public void close() throws Exception {
            System.out.println("TryWithResources.Resource2.close()");
        }
    }

当我运行这个示例时,我得到的唯一输出是 RuntimeException,这意味着 Resource1 没有关闭。这是预期的,因为它没有在 try-with-resources 中初始化。

但是,这是预期的结果吗,还是我错过了什么?

因为,如果这实际上是它应该工作的方式,那么在我看来,这种新语法实际上消除了最初由 try-with-resources 语句带来的很多安全性。

有人可以确认一下情况是否属实吗? 而且,如果是的话,我们为什么要在多个资源上使用这种语法并冒这个风险?

java java-9 try-with-resources autocloseable
2个回答
7
投票

我认为您假设“初始化”发生在

try
语句中。构造函数在到达 try-with-resources 之前抛出异常。换句话说,
try (r1; r2) {
行本身并不初始化资源,它只是将它们引用为变量。它与在
try
块中初始化资源不同:
try (r1; Resource2 r2 = new Resource2()) { // this causes r1 to close if r2 throws an exception

话虽如此,您的观点是对的,新语法(访问最终变量)提供了灵活性,但代价是可能无法关闭以前创建的资源(如您的案例所示)。就我个人而言,我从来没有理由使用这种新语法。我没有想到不在 
try

语句中创建资源的充分理由,毕竟关闭资源后就没有任何意义了。

    


3
投票
try-with-resources

机制发挥作用,您应该将初始化代码放入

try
中。您的初始化似乎发生在 1 行之前。如果你愿意:
  public static void main(String[] args) {
    try (Resource1 r1 = new Resource1(); Resource2 r2 = new Resource2()) {
      System.out.println("TryWithResources.main() try");
    } catch (Exception e) {
      System.out.println("TryWithResources.main() catch");
    }
  }

将打印:

TryWithResources.Resource1.close() TryWithResources.main() catch

所以你的代码应该读成这样:
“我想自动关闭

r1

r2
但我更喜欢自己初始化它”

我的版本应该读成这样:

“我想自动关闭

r1

r2
,而且我想将其初始化为
try
块的一部分”

    

© www.soinside.com 2019 - 2024. All rights reserved.