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

Java 为什么我们必须在try-with-resource块中声明和定义资源?,java,try-with-resources,autocloseable,Java,Try With Resources,Autocloseable,上面的工作很好。但当我这么做的时候 try(PrintWriter f = new PrintWriter(new BufferedWriter(new FileWriter("abc.txt")));) {} catch(IOException ex) { ex.printStackTrace(); } 它会抛出错误。为什么会这样?我正在测试这个新特性,我认为我将采用第二种方法,在try-catch语句之后,我将打印资源PrintWriter f——如果try-with-resour

上面的工作很好。但当我这么做的时候

try(PrintWriter f = new PrintWriter(new BufferedWriter(new FileWriter("abc.txt")));) 
{}
catch(IOException ex) 
{
  ex.printStackTrace();
}
它会抛出错误。为什么会这样?我正在测试这个新特性,我认为我将采用第二种方法,在
try-catch语句
之后,我将打印资源
PrintWriter f
——如果try-with-resource语句按预期工作,则该值应为空。为什么不允许第二条路


还有,我如何用方法1测试它呢?

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

所以这个代码

PrintWriter f;
try(f = new PrintWriter(new BufferedWriter(new FileWriter("abc.txt")));) 
{}
catch(IOException ex) 
{
  ex.printStackTrace();
}
实际上转化为

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

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

这就是最初的目的,将您从臃肿的代码中解救出来,并允许您处理
try
block,而将其余部分留在JVM上。另请看Oracle对此有何评论。

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

所以这个代码

PrintWriter f;
try(f = new PrintWriter(new BufferedWriter(new FileWriter("abc.txt")));) 
{}
catch(IOException ex) 
{
  ex.printStackTrace();
}
实际上转化为

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

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

这就是最初的目的,将您从臃肿的代码中解救出来,并允许您处理
try
block,而将其余部分留在JVM上。另请看Oracle对此有何评论。

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

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

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

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


    • 不太确定,但做了一些复杂的猜测:

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

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

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


        • 我相信下面的代码回答了您的问题,并带来了意想不到的结果

          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) {}
               }
          }
          
          输出:

          java.io。PrintWriter@1fc4bec

          但是,没有向文件中添加任何内容,因为写入程序已被try关闭

          编辑:如果要使用TWR,请编写一个实现AutoClosable的类,例如:

              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();
          
          输出:

          我要开门了


          我要结束了

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

          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) {}
               }
          }
          
          输出:

          java.io。PrintWriter@1fc4bec

          但是,没有向文件中添加任何内容,因为写入程序已被try关闭

          编辑:如果要使用TWR,请编写一个实现AutoClosable的类,例如:

              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();
          
          输出:

          我要开门了


          我正在结束

          可能对您有帮助,并且。请阅读更多关于错误的信息?这可能会对您有帮助,并且。请阅读更多关于错误的信息?这可能会有帮助您的答案没有说明为什么禁止使用外部变量来进行此操作。JVM仍然可以做所有这些事情,即使有来自外部的变量。我想这是因为您可以将该变量绑定到
          try
          block中的其他内容,比如
          null
          ,这意味着JVM可能无法正确关闭资源。无论如何,这已经被证实了,我试图给它添加一些新的东西-你的回答没有说明为什么禁止使用外部变量。JVM仍然可以做所有这些事情,即使有来自外部的变量。我想这是因为您可以将该变量绑定到
          try
          block中的其他内容,比如
          null
          ,这意味着JVM可能无法正确关闭资源。无论如何,这已经被证实了,我想给它添加一些新的东西-