【问题标题】:try-with-resources details [duplicate]尝试资源详细信息[重复]
【发布时间】:2015-09-06 11:27:09
【问题描述】:

我们使用 3 个基本步骤处理对象:

  1. 声明
  2. 实例化
  3. 初始化

我的问题是关于在 () 部分的 try-with 中必须执行哪些步骤才能自动关闭要制作的资源。

示例 1 - FileReader 对象会在此代码中自动关闭:

try (BufferedReader br = new BufferedReader(new FileReader(filePath)))
{
//some code;
} 

示例 2 - buf2 是否会在此代码中自动关闭:

private static BufferedReader buf1;

public static void main(String[] args) throws IOException {
    //some code
    try (BufferedReader buf2 = buf1)
    {

    } 
 }

附:有人认为这个问题与 Try With Resources vs Try-Catch 重复。它不是。这个问题是关于 try-catch 和 try-with-resources 之间的区别。我的问题是关于试用的细节。

【问题讨论】:

  • 听起来像是一道作业题,但这里有一个提示:try-with-resources 要求声明的变量实现AutoCloseable,并隐式调用close()终于阻塞了。
  • 准备(学习)认证的功课。谷歌搜索 OCPJP 甚至会链接到“甲骨文大学”网站。 --- 也许The try-with-resources Statement 上的 Java 教程的第一段会对你有所帮助。
  • 如果你真的很想学习 Java,你不应该害怕尝试。创建一个 AutoCloseable 类。在 close() 方法中添加 System.out.println 语句。将上述代码与该类一起使用,而不是 BufferedReader。看看有没有打印出来。或者只是在 BufferedReader.close() 中添加一个调试器断点,看看是否到达。
  • @JB Nizet 感谢您抽出宝贵时间。我不害怕。问题是我更喜欢理解原则而不是任何情况。我写在这里是因为我希望有人能给出自动关闭的主要原则。

标签: java


【解决方案1】:

只要需要语言相关的详细信息,最完整的参考就是 Java 语言规范(只需 Google 即可)。对于try-with-resources 声明,您可以阅读section 14.20.3,其中声明如下:

try ({VariableModifier} R Identifier = Expression ...)
    Block

被翻译成

{
   final {VariableModifierNoFinal} R Identifier = Expression; 
   Throwable #primaryExc = null;
   try ResourceSpecification_tail
      Block catch (Throwable #t) {
         #primaryExc = #t;
         throw #t;
      } finally {
         if (Identifier != null) {
            if (#primaryExc != null) { 
               try { 
                  Identifier.close(); 
               } catch (Throwable #suppressedExc) { 
                  #primaryExc.addSuppressed(#suppressedExc);
               }
            } else {
               Identifier.close();
            }
         }
     }
}

在您的第一个示例中,资源 RBufferedReaderIdentifierbrExpressionnew BufferedReader(new FileReader(filePath))。因此,只有 BufferedReader 在隐式 finally 块中被关闭。 finally 块不会在 FileReader 上调用 close,因为它不是资源声明本身的一部分。 然而BufferedReader.close() 的实现会在内部调用包装好的FileReaderclose 方法。所以第一个问题的答案是肯定的,因为包装对象关闭了它(遵循资源在释放自身时应该释放任何包装资源的常识),不是因为try-有资源。

在第二个例子中:

private static BufferedReader buf1;

public static void main(String[] args) throws IOException {
    //some code
    try (BufferedReader buf2 = buf1)
    {

    } 
}

答案取决于some code。这里buf2buf1 都指向内存中的同一个对象。如果这个“一些代码”将buf1 初始化为某个对象,那么这个对象将被关闭,因为buf2 也引用了它。如果不是并且buf1 为空(因此buf2 为空),则不会关闭任何内容,因为上面显示的隐式finally 中的空检查。

【讨论】:

    【解决方案2】:
    1. FileReader 将被关闭。但这不是因为它在 try 语句中。这是因为当BufferedReader 关闭时,它也会在FileReader 上调用close()。举个反例,我有一个名为X 的类,它实现了AutoCloseable。该类在其构造函数中需要一个Foo 对象。所以我写:

      try (X x = new X(new Foo())) {
      
      }
      

    Foo 会被关闭吗?它甚至没有实现AutoCloseable

    1. 我写了以下代码来测试这个:

      BufferedReader buf1 = null;
      try (BufferedReader buf2 = buf1) {
      
      }
      

    而且它工作得非常好,没有例外!我的猜测是,在 try 语句的末尾,它会检查对象是否为空。如果不是,则关闭它。所以在这种情况下,由于 buf2 为 null,所以无法关闭。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-18
      • 2019-04-30
      • 1970-01-01
      • 1970-01-01
      • 2019-03-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多