【问题标题】:Why do we have to do both declare and define resources in try-with-resource block? [duplicate]为什么我们必须在 try-with-resource 块中声明和定义资源? [复制]
【发布时间】:2013-10-17 10:06:56
【问题描述】:
try(PrintWriter f = new PrintWriter(new BufferedWriter(new FileWriter("abc.txt")));) 
{}
catch(IOException ex) 
{
  ex.printStackTrace();
}

以上工作正常。但是当我这样做时

PrintWriter f;
try(f = new PrintWriter(new BufferedWriter(new FileWriter("abc.txt")));) 
{}
catch(IOException ex) 
{
  ex.printStackTrace();
}

它会抛出错误。为什么会这样?我正在测试这个新功能,我认为我会采用第二种方法,在try-catch statement 之后会打印资源PrintWriter f - 如果try-with-resource 语句按预期工作,则它应该为空。为什么不允许第二种方式?

另外我怎么能通过方法1测试它?

【问题讨论】:

标签: java try-with-resources autocloseable


【解决方案1】:

因为try-with-resources 实际上为您添加了finally 块以便在使用后关闭资源,所以它们无论如何都不应该可用(在您离开try 块之后)。

所以这段代码

try(PrintWriter f = new PrintWriter(new BufferedWriter(new FileWriter("abc.txt")));) {

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

其实翻译成

PrintWriter f = null;
try {
    f = new PrintWriter(new BufferedWriter(new FileWriter("abc.txt")));) 
     // now do something
} catch(IOException ex) {
    ex.printStackTrace();
}
finally {
    try {
        f.close();
        catch(IOException ex) {}
     }
}

所以这是最初的目的,将您从臃肿的代码中解救出来,让您只关心 try 块并将其余部分留在 JVM 上。另请参阅 Oracle docs 对此有何评论。

【讨论】:

  • 您的回答表明没有理由禁止为此使用外部变量。即使使用来自外部的变量,JVM 仍然可以完成所有这些工作。
  • 我想这是因为您可以将该变量绑定到 try 块内的其他内容,例如 null,这意味着 JVM 可能无法正确关闭资源。
  • 无论如何,这已经被确认了,我正在尝试添加一些新的东西 - stackoverflow.com/questions/13836486/…
【解决方案2】:

我相信下面的代码回答了你的问题,结果出乎意料。

    PrintWriter t = null;
    try( PrintWriter f = new PrintWriter( new BufferedWriter(
            new FileWriter( "abc.txt" ) ) ) ) {
        f.println( "bar" );
        t = f;
    } catch( IOException ex ) {
        ex.printStackTrace();
    }
    System.out.println( t );
    t.println( "foo" );
    t.close();

输出:

java.io.PrintWriter@1fc4bec

但是,没有任何内容添加到文件中,因为编写器已被尝试关闭。

编辑:如果你想玩TWR,写一个实现AutoClosable的类,例如:

public class Door implements AutoCloseable {
    public Door() {
        System.out.println( "I'm opening" );
    }
    public void close() {
        System.out.println( "I'm closing" );
    }
    public static void main( String[] args ) {
        try( Door door = new Door() ) { }
    }

}

输出:

我要开门了

我要关门了

【讨论】:

    【解决方案3】:

    不完全确定,但做了一些复杂的猜测:

    • catch 块之后的 f 值可能未定义。因此,您必须添加各种检查来验证对象是否已创建、使用和/或关闭。但是,如果您需要所有这些检查,那么首先不使用该习语会更简单。

    • JIT 可以使用块局部变量愉快地优化代码。

    • 在 try 块期间不得将 AutoClosure 变量设置为不同的变量,但可以在之后设置。也许这对于 JIT 来说太复杂了,无法检查。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-26
      • 1970-01-01
      • 1970-01-01
      • 2020-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多