为什么我们必须同时在try-with-resource块中声明和定义资源?

时间:2013-10-17 10:06:57

标签: java try-with-resources autocloseable

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语句按预期工作,则该值应为null 。为什么不允许第二种方式?

我怎样才能通过方法1进行测试?

3 个答案:

答案 0 :(得分:4)

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

所以这段代码

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对此有何评论。

答案 1 :(得分:1)

我相信下面的代码可以回答你的问题,并带来意想不到的结果。

    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() ) { }
    }

}

输出:

我正在打开

我正在关闭

答案 2 :(得分:0)

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

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

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

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