【问题标题】:Is closing resources in try block accepted?是否接受尝试块中的关闭资源?
【发布时间】:2015-06-21 10:16:35
【问题描述】:

一本关于 Java 的初学者书籍中包含以下代码。这本书也很好地解释了异常,并且由于我了解异常是如何工作的,所以我对以下代码提出了一个问题。

由于某种原因,如果 FileWriter 类抛出异常,writer.close() 将不会被执行。因此,我认为关闭 writer 对象的最佳位置是在 finally 块中。甚至在此之前,我已经看到许多这样编写的代码,其中资源将在 try 块本身中关闭。我认为这样做没有任何意义。只有在没有异常的情况下才会关闭资源。

我错了吗?在java中关闭资源的最佳方法是什么?我们不应该编写如下代码吗?

 public static void main(String[] args) {

       try{
         FileWriter writer = new FileWriter("file.txt");
         writer.write("i am writing");
         writer.close();
       }catch(IOException e){
           ex.printStackTrace();
       }

    }

【问题讨论】:

  • 你说得对,最好在 finally 块中关闭 writer 对象,但是,由于该 writer 对象是 try catch 的一部分,因此无法在 finally 中访问它。为此,您需要在 try 块之外声明变量。
  • 你是对的,正确的地方是最终的。当然,这可能会在 final 中引发另一个异常;所以有些人不喜欢那样。顺便说一句:现在,应该使用 try-with-resources
  • 从 Java 7 开始你也可以使用 try-with-resources

标签: java exception io


【解决方案1】:

如果您使用的是 Java 7,最好的方法是使用资源尝试。见https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

 try (FileWriter writer = new FileWriter("file.txt")) {
   writer.write("i am writing");
 }

【讨论】:

    【解决方案2】:

    我同意@cyber-rookie,最好在 finally 块中关闭资源。

    Java 7 引入了“try-with-resources”以减少编程错误...

    https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

    你现在可以写...

        try (FileWriter writer = new FileWriter("file.txt")) {
            writer.write("i am writing");
        } catch (IOException e) {
            e.printStackTrace();
        }
    

    编译器会为你添加额外的代码在块的末尾关闭编写器

    【讨论】:

    • 如果我要关闭多个资源怎么办?
    • @DesirePRG - 您可以用分号分隔 then,例如... try ( Resource res1 = new ClosableResource(...); Resource res2 = new ClosableResource(...) ) { ... }
    【解决方案3】:

    你是对的,资源应该在finally块中关闭。

    java 7 开始,您也可以将 try-with-resource 用作:

    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
    

    因为BufferedReader实例是在try-with-resource语句中声明的,如果这些资源实现AutoCloseable接口,无论try语句是否完成normally or abruptly都会关闭。

    【讨论】:

      【解决方案4】:

      根据我的经验,我们会使用 try-catch 的 finally 子句:

      public static void main(String[] args) {
      
          FileWriter writer = null;
          try {
              writer = new FileWriter("file.txt");
              writer.write("i am writing");
      
          } catch (IOException ex) {
              ex.printStackTrace();
      
          } finally {
              try {
                  if (writer != null)
                      writer.close();
              } catch (IOException ex) {
                  ex.printStackTrace();
              }
      
          }
      }
      

      PS:把这个放在单独的方法中,抛出异常,让使用这个的类处理异常。

      【讨论】:

      • 看来我落后了,java7 现在有一种更简洁的方式来处理这个问题。
      【解决方案5】:

      回答评论以在 try with 资源块中添加多个资源:

      try(FileWriter writer = new FileWriter("file.txt"); BufferedReader reader = new BufferedReader(new FileReader("file.txt"))){
              // you can put many AUTOCLOSEABLE objects in try with resource. Just seperate them with ";"  
          } catch (IOException e) {
              e.printStackTrace();
          }
      

      【讨论】:

        【解决方案6】:

        在工作中(Java 6),我们在 TRY 块中关闭资源,然后在 FINALLY 块中进行防御性关闭。

        BufferedReader bufferedReader;
        try {
          //initialize and do something with the bufferedReader
           bufferedReader.close();
        } catch (FileNotFoundException ex) {
            // notify the user 
        } catch (IOException ex) {
            // notify the user 
        } finally {
            if (bufferedReader != null) {
                try {
                   //defensive close
                    bufferedReader.close();
                } catch (IOException ex) {
                    // this will be thrown if bufferedReader is already closed (in Try block, so can be leave to blank
        
                }
            }
        }
        

        【讨论】:

        • 为什么不只在内部try块中做close()?
        • @Bret - 因为在 try 块中使用 bufferedReader 时,您可能会遇到异常,导致 try 块中的 bufferedReader.close() 没有被执行,这就是在 finally 块中关闭的地方救援
        • 如果你从“try”块中删除它,它无论如何都会在“finally”块中执行。如果这引发异常,它将在第二个 catch 块中处理,对吗?如果你同时保留这两个,那么如果第一个工作(由于正常操作),它将在 finally 块中再次调用,并且总是会抛出异常(并处理它),因为它已经关闭了一次(假设如果已经关闭,close 的实现总是会抛出异常......)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-09
        • 2012-07-04
        • 2013-02-10
        • 2011-03-30
        • 2021-11-26
        • 1970-01-01
        相关资源
        最近更新 更多