【问题标题】:java try finally block to close streamjava try finally 阻止关闭流
【发布时间】:2011-11-05 16:22:44
【问题描述】:

我想在 finally 块中关闭我的流,但它会抛出一个 IOException,所以看起来我必须在我的 finally 块中嵌套另一个 try 块才能关闭流。这是正确的方法吗?好像有点笨重。

代码如下:

 public void read() {
    try {
        r = new BufferedReader(new InputStreamReader(address.openStream()));
        String inLine;
        while ((inLine = r.readLine()) != null) {
            System.out.println(inLine);
        }
    } catch (IOException readException) {
        readException.printStackTrace();
    } finally {
        try {
            if (r!=null) r.close();
        } catch (Exception e){
            e.printStackTrace();
        }
    }


}

【问题讨论】:

标签: java file-io stream try-catch finally


【解决方案1】:

是的,它笨重、丑陋且令人困惑。一种可能的解决方案是使用Commons IO,它提供了closeQuietly 方法。

此页面右侧的“相关”列中有许多问题实际上是重复的,我建议您查看这些问题以了解其他处理此问题的方法。

【讨论】:

    【解决方案2】:

    看起来有点笨重。

    是的。至少 java7 对资源的尝试可以解决这个问题。

    在 java7 之前,你可以创建一个 closeStream 函数来吞噬它:

    public void closeStream(Closeable s){
        try{
            if(s!=null)s.close();
        }catch(IOException e){
            //Log or rethrow as unchecked (like RuntimException) ;)
        }
    }
    

    或者将 try...finally 放在 try catch 中:

    try{
        BufferedReader r = new BufferedReader(new InputStreamReader(address.openStream()));
        try{
    
            String inLine;
            while ((inLine = r.readLine()) != null) {
                System.out.println(inLine);
            }
        }finally{
            r.close();
        }
    }catch(IOException e){
        e.printStackTrace();
    }
    

    它更冗长,finally 中的一个异常会在 try 中隐藏一个,但它在语义上更接近 Java 7 中引入的 try-with-resources

    【讨论】:

    • 我选择了第二种方法,因为它更干净、更易读。这非常重要,因为我们希望避免任何内存泄漏。
    【解决方案3】:

    您在 finally 中的方法是正确的。如果您在 finally 块中调用的代码可能会引发异常,请确保您要么处理它,要么记录它。永远不要让它从 finally 块中冒出来。

    在 catch 块中,您正在吞噬异常 - 这是不正确的。

    谢谢...

    【讨论】:

      【解决方案4】:

      此外,如果您使用的是 Java 7,则可以使用 try-with-resources statement

      try(BufferedReader r = new BufferedReader(new InputStreamReader(address.openStream()))) {
          String inLine;
          while ((inLine = r.readLine()) != null) {
              System.out.println(inLine);
          }
      } catch(IOException readException) {
          readException.printStackTrace();
      }           
      

      【讨论】:

      • 在不登录的情况下在堆栈跟踪中打印问题是一个问题,所以我建议人们使用log.debug(readException.getMessage());
      • @surendrapanday 我不明白为什么这应该是一个问题。由于 12 个因素,日志记录范式发生了变化,因此记录到标准输出不再是问题。您将所有内容记录到标准输出,就像您将流程视为管道一样,您可以按照自己的方式处理日志,而无需接触您的代码。
      【解决方案5】:

      在 Java 7 中,您可以这样做...

      try (BufferedReader r = new BufferedReader(...)){
           String inLine;
           while ((inLine = r.readLine()) != null) {
                System.out.println(inLine);
           }
      } catch(IOException e) {
         //handle exception
      }
      
      • 在 try 块中声明变量要求它实现 AutoCloseable
      • 在 try 块中声明变量也会将其范围限制为 尝试阻止。
      • 在 try 块中声明的任何变量都会在 try 块退出时自动调用 close()

      它被称为Try with resources statement

      【讨论】:

        【解决方案6】:

        就像提到 Commons IO 库的答案一样,Google Guava Libraries 对 java.io.Closeable 有类似的帮助方法。班级是com.google.common.io.Closeables。您要查找的函数类似地命名为 Commons IO:closeQuietly()。

        或者你可以自己滚动关闭一堆这样的:Closeables.close(closeable1, closeable2, closeable3, ...) :

        import java.io.Closeable;
        import java.util.HashMap;
        import java.util.Map;
        
        public class Closeables {
          public Map<Closeable, Exception> close(Closeable... closeables) {
        
          HashMap<Closeable, Exception> exceptions = null;
        
          for (Closeable closeable : closeables) {
            try {
              if(closeable != null) closeable.close();
            } catch (Exception e) {
                if (exceptions == null) {
                  exceptions = new HashMap<Closeable, Exception>();
                }
                exceptions.put(closeable, e);
              }
            }
        
            return exceptions;
          }
        }
        

        它甚至会返回任何抛出的异常的映射,如果没有则返回 null。

        【讨论】:

        • 无论谁对我的答案投了反对票,您能否解释一下原因,以便我可以从中学习?
        • 我会支持你,这样它就可以平衡了。 Guava 是一个很棒的图书馆
        【解决方案7】:
        public void enumerateBar() throws SQLException {
            Statement statement = null;
            ResultSet resultSet = null;
            Connection connection = getConnection();
            try {
                statement = connection.createStatement();
                resultSet = statement.executeQuery("SELECT * FROM Bar");
                // Use resultSet
            }
            finally {
                try {
                    if (resultSet != null)
                        resultSet.close();
                }
                finally {
                    try {
                        if (statement != null)
                            statement.close();
                    }
                    finally {
                        connection.close();
                    }
                }
            }
        }
        
        private Connection getConnection() {
            return null;
        }
        

        source。 这个示例对我很有用。

        【讨论】:

          【解决方案8】:

          我在您的代码中注意到的第一件事是您的代码中缺少花括号 { },如果您查看它的话。您还需要将r 的值初始化为null,因此首先需要将空值传递给对象,这样如果您编写的条件可以进行not null 条件检查并让您关闭流。

          【讨论】:

            猜你喜欢
            • 2012-09-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-08-27
            • 2015-09-01
            • 1970-01-01
            • 2014-08-29
            相关资源
            最近更新 更多