0

示例代码:

    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 语句初始化的所有资源都将关闭。
  • 仅当资源初始化为非空值时才关闭资源。
  • 如果 try 块和 try-with-resources 语句都抛出异常,则该方法抛出 try 块抛出的异常;从 try-with-resources 语句抛出的异常被抑制。

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

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

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

4

3 回答 3

0

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 块,它可能会将两者合并。
  • 使用一些合成函数来处理相同的捕获。

如果您有兴趣,E. Mandrikov 的这个演示文稿解释了编译器的作用以及它是如何让代码覆盖头疼的。

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

  • ac1初始化可能会失败,在这种情况下,变量将是null(默认值)。
  • ac2初始化可能会失败,ac1不会为空。
  • ac1并且ac2可能会起作用,在这种情况下,只有doWhatever()会负责失败。

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

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

然后,AutoCloseable除非ac1()ac2::close. 垃圾收集器不会调用ac1::close.

于 2018-11-01T03:43:44.147 回答
0

1) 是的。如果资源初始化成功并且 try 块有异常,则资源将被关闭,就像我们在 finally 块中不使用资源进行尝试一样。

2)文档说(修改很少):

如果不使用资源进行尝试,如果在一个方法中,read() 和 close()(在 finally 块中)都抛出异常,则该方法会抛出从 finally 块中抛出的异常;从 try 块抛出的异常被抑制。相比之下,使用 try with resource 时,如果 try 块和 try-with-resources 语句都抛出异常,则该方法将抛出 try 块抛出的异常;从 try-with-resources 块抛出的异常被抑制。

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

于 2018-11-01T03:18:37.170 回答
0

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

目前尚不清楚您所引用的“资源将被关闭,无论 try 语句是正常完成还是突然完成”。然而,如果在资源规范中尝试初始化资源会引发异常,那么不,该资源不会关闭,因为它没有被初始化为非空值(您的第二个要点,这是 JLS 文本的摘录) .

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

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

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

还要注意,JLS使用传统的//和显式资源闭包try-with-resources 语句转换为等效代码。如果您正在为 try-with-resources 的语义而苦苦挣扎,那将是一个很好的考虑资源。trycatchfinally

于 2018-11-01T03:35:15.657 回答