36

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

这是代码:

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


}
4

8 回答 8

36

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

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();
}           
于 2011-08-28T23:56:11.460 回答
27

它似乎有点笨拙。

这是。至少 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 。

于 2011-08-28T23:22:16.050 回答
23

在 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 块中。
  • close()在 try 块中声明的任何变量都会在 try 块退出时自动调用。

它被称为Try with resources 声明

于 2011-08-28T23:57:15.700 回答
9

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

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

于 2011-08-28T23:21:02.567 回答
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。

于 2011-08-29T01:06:32.517 回答
2

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

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

谢谢...

于 2011-08-28T23:34:22.877 回答
0
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;
}

来源。这个样本对我很有用。

于 2013-03-29T04:51:10.637 回答
0

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

于 2019-02-21T03:36:56.430 回答