如果语句抛出异常(初始化问题),try with resource语句中的单个资源是否不会关闭

Will the single resource in try with resource statement be not closed if there is an exception thrown from the statement (initialization issue)

示例代码:

    class TestCharStream {
        public static void main(String[] args){
// Assume specified file is not available in the location
            try (Reader reader = new FileReader("C:\TestData\test123.txt")) {
                System.out.println("Entered Try block");
                int content;
                while ((content = reader.read()) != -1) {
                    System.out.print((char) content);
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

由于文件不可用,将抛出'FileNotFoundException',资源初始化失败。

根据 Java SE7 规范,我理解以下与 'try with resources' 语句相关的要点

我有关于关闭资源、抑制与上述指定点相关的异常的问题

1) 上面的示例代码案例(即资源初始化失败)是否属于..无论try语句是正常完成还是突然完成,资源都会被关闭.这是否仅适用于在 try with resources 语句中成功初始化的资源并且 try 块中存在错误?

2) 如果在初始化资源时抛出异常(如示例),则属于初始化不成功的场景。在这种情况下,我们如何遇到在 try-with-resources 语句中抛出异常的场景(这基本上只能在初始化期间发生)?是关闭资源抛出的异常吗?

1) 是的。如果资源初始化成功,如果try块出现异常,资源将被关闭,就像我们在finally块中一样,没有try with resource。

2) 文档说(稍作修改):

Without try with resource, If in a method, both read() and close() (in finally block) throw exceptions, then the method throws the exception thrown from the finally block; the exception thrown from the try block is suppressed. In contrast, with try with resource, if exceptions are thrown from both the try block and the try-with-resources statement, then the method throws the exception thrown from the try block; the exception thrown from the try-with-resources block is suppressed.

如您所述,第二点中 try-with-resource 的异常将来自关闭资源。

1) Does the above example code case (i.e. resource failed to initialize) not fall under the scenario ..resource will be closed regardless of whether the try statement completes normally or abruptly. Is this applicable only for resources initialized successfully in try with resources statement and there is an error in the try block?

不清楚您在 "resource will be closed regardless of whether the try statement completes normally or abruptly" 中指的是什么。然而,如果在资源规范中尝试初始化资源抛出异常,则不,该资源未关闭,因为它未初始化为非空值(您的第二个要点,这是 JLS 文本的摘录) .

如果资源规范中有多个资源,那么有可能在其中一个初始化抛出之前先初始化一些资源;在这种情况下,成功初始化为非空值的那些将被关闭。

2) If exceptions are thrown while initializing resources(like the example), this will fall under unsuccessful initialization scenario. In this case, how do we come across the scenario of exceptions thrown in a try-with-resources statement (which could basically occur only during initialization) at all? Is it the exceptions thrown while closing the resource?

try-with-resources 语句是复合语句,包含从初始 try 关键字到关联块的所有内容,并包括任何 catchfinally 子句.主要重点是在 try 块内部抛出异常时正确清理。规范中有关资源初始化期间发生异常的情况的位可以根据 N-resource try-with-resources 语句和 N 之间的等效性来理解 嵌套的单资源 try-with-resources 语句。

还要注意,JLS 使用传统的 try / catch / finally 和显式将 try-with-resources 语句的 a translation 呈现为等效代码资源关闭。如果您正在为 try-with-resources 的语义苦苦挣扎,那将是一个值得考虑的好资源。

try-with-resources 是旧语法的语法糖,使用旧语法编写它可以帮助您理解它的作用:

这种例子:

  try (AutoCloseable ac1 = ac1(); AutoCloseable ac2 = ac2()) {
    ac2.doWhatever();
  } catch (Exception e) { 
    fail(e);
  }

改写成这样:

  AutoCloseable ac1 = null;
  try {
    ac1 = ac1();
    AutoCloseable ac2 = null;
    try {
      ac2 = ac2();
      ac2.doWhatever();
    } catch (Exception e) { 
      fail(e);
    } finally {
      if (ac2 != null) ac2.close();
    }
  } catch (Exception e) { 
    fail(e);
  } finally {
    if (ac1 != null) ac1.close();
  }

编译器可能会优化代码:

  • finally 块只能有一个,它可能会将两者合并。
  • 使用一些合成函数来处理相同的捕获。

如果您有兴趣,这篇presentation by E. Mandrikov解释了编译器的作用以及代码覆盖率如何令人头疼。

如你所见,它可能在初始化部分失败:

  • ac1 初始化可能会失败,在这种情况下,变量将为 null(默认值)。
  • ac2 初始化可能失败,ac1 不会为空。
  • ac1ac2 可能有效,在这种情况下,只有 doWhatever() 会导致失败。

如果ac2依赖于ac1,并且不在资源列表中,例如:

try (AutoCloseable ac2 = ac2(ac1())) {
  ...
}

然后,由 ac1() 构建的 AutoCloseable 将不会关闭,除非它在 ​​ac2::close 中关闭。并且垃圾收集器不会调用 ac1::close.