为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

缥缈止盈 2021-12-22 16:44:28
示例代码:    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) 上面的示例代码情况(即资源初始化失败)是否不属于..resource 将被关闭的情况,无论try 语句是正常完成还是突然完成。这是否仅适用于在 try with resources 语句中成功初始化的资源并且 try 块中存在错误?2) 如果在初始化资源时抛出异常(如示例),则属于初始化不成功的情况。在这种情况下,我们如何遇到 try-with-resources 语句中抛出异常的场景(基本上只能在初始化期间发生)?是关闭资源时抛出的异常吗?
查看完整描述

3 回答

?
杨魅力

TA贡献1811条经验 获得超6个赞

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

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

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

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

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

注意,那就是,在JLS礼物翻译一试,与资源语句为等效代码使用传统trycatch/finally和明确的资源闭合。如果您正在为 try-with-resources 的语义而苦苦挣扎,那将是一个值得考虑的好资源。


查看完整回答
反对 回复 2021-12-22
?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

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

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

没有try with resource,如果在一个方法中,read()和close()(在finally块中)都抛出异常,则该方法抛出finally块中抛出的异常;从 try 块抛出的异常被抑制。相比之下,使用try with resource,如果try块和try-with-resources语句都抛出异常,则该方法抛出try块抛出的异常;从 try-with-resources 块抛出的异常被抑制。

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


查看完整回答
反对 回复 2021-12-22
?
MYYA

TA贡献1868条经验 获得超4个赞

在尝试与-资源是在旧的语法和使用旧的语法,可以帮助你了解它写它的语法糖:


这种例子:


  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.



查看完整回答
反对 回复 2021-12-22
  • 3 回答
  • 0 关注
  • 423 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信