-3

考虑 :

public static void read(String filename) throws IOException {
    String charsetName = "UTF-8";
    InputStream file = new FileInputStream(filename); // say no problem
    InputStreamReader reader = new InputStreamReader(file, charsetName);
    BufferedReader buffer = new BufferedReader(reader);
    try {
        buffer.readLine();
    } finally {
        try {
            buffer.close();
        } catch (IOException e) {
            // report at least
            e.printStackTrace();
        }
    }
}

如果 new InputStreamReader(file, charsetName)throws UnsupportedEncodingExceptionbuffer.close();则永远不会调用该行。另一种方法是额外的冗长:

InputStream file = new FileInputStream(filename);
try {
    InputStreamReader reader = new InputStreamReader(file);
    try {
        BufferedReader buffer = new BufferedReader(buffer);
        try {
            buffer.readLine();
        } finally {
            buffer.close(); // should catch
        }
    } finally {
        reader.close(); // should catch
    }
} finally {
    file.close(); // should catch
}

并且它不必要地关闭了所有流(虽然output.close();应该足够了 - 实际上,如果成功,它们中的任何一个都足够了 -请参阅 Skeet 代码中的注释)。

包装构造函数

BufferedReader buffer = new BufferedReader(
              new InputStreamReader(new FileInputStream(filename), charsetName));

本质上只是隐藏问题。

请注意,我在这里使用@TomHawtin-tackline 建议的 try-finally 习语- 但更常见的方法是:

public static void read(String filename) throws IOException {
    String charsetName = "UTF-8";
    InputStream file = null;
    InputStreamReader reader = null;
    BufferedReader buffer = null;
    try {
        file = new FileInputStream(filename);
        reader = new InputStreamReader(file, charsetName);
        buffer = new BufferedReader(reader);
        buffer.readLine();
    } finally {
        try {
            if(buffer != null) buffer.close();
        } catch (IOException e) {
            // report at least
            e.printStackTrace();
        }
        // Rinse and repeat for the rest
    }
}

一样尴尬。

问题 :

你会如何处理这个案子?
将 :

public static void read(String filename) throws IOException {
    String charsetName = "UTF-8";
    InputStream file = new FileInputStream(filename);
    try {
        InputStreamReader reader = new InputStreamReader(file, charsetName);
        BufferedReader buffer = new BufferedReader(reader); // Eclipse warning
        buffer.readLine();
        // notice that if these were out put streams we SHOULD FLUSH HERE
    } finally {
        try {
            file.close();
        } catch (IOException e) {
            // report at least
            e.printStackTrace();
        }
    }
}

做 ?换句话说,当有超过 2 个包裹的流时,关闭最里面的流(与通常 要求的相反)将是最干净的解决方案?是否存在装饰器也应该关闭的情况?请参阅此处的示例点。请注意 Eclipse 警告:finally

资源泄漏:“缓冲区”永远不会关闭

日食是对的吗?

这是 Java 6 - 我提醒你,Android 只是 Java 6。尝试一劳永逸地在某些实用程序类中排除 IO 代码

4

2 回答 2

2

在您的最后一种方法中,Resource leak根据关闭流的规则,eclipse 显示的警告是正确的。关闭最里面的流只是关闭该流,而不是关闭该流的其他流。但关闭最外层流是一次性操作,会自动关闭所有底层流。如文章始终关闭流中所述:

如果多个流被链接在一起,那么关闭最后一个构建的流,因此处于最高抽象级别,将自动关闭所有底层流。因此,只需在一个流上调用 close 即可关闭(并刷新,如果适用)整个系列的相关流。

因此,在我看来,以下代码是您的案例的解决方案:

public static void read(String filename) throws IOException {
    String charsetName = "UTF-8";
    InputStream file = null;
    InputStreamReader reader = null;
    BufferedReader buffer = null;
    try 
    {
        file = new FileInputStream(filename);                
        reader = new InputStream(file,charsetName);
        buffer = new BufferedReader(reader);
        buffer.readLine();
    } 
    finally 
    {
         closeQuietly(buffer,reader,file);
    }
}

编辑
正如@jtahlborn 所建议的,在 finally 块中编写的代码被包装在一个实用方法中,如下所示:

public static void closeQuietly(Closeable... closeables) 
{ 
    if(closeables == null) 
    { 
        return; 
    } 
    for (Closeable c : closeables) 
    { 
        doCloseQuietly(c); 
    } 
} 
public static void doCloseQuietly(Closeable c)
{
    try
    {
        if (c != null)
        {
            c.close();
        }
    }
    catch (IOException ex)
    {
        ex.printStackTrace();
    }
}
于 2013-05-03T18:14:00.037 回答
-1

第二种模式(检查空一)可以修改为:

public static void readSO2(String filename) throws IOException {
    String charsetName = "UTF-8";
    InputStream file = null;
    InputStreamReader reader = null;
    BufferedReader buffer = null;
    try {
        file = new FileInputStream(filename);
        reader = new InputStreamReader(file, charsetName);
        buffer = new BufferedReader(reader);
        buffer.readLine();
    } finally {
        try {
            if (buffer != null) buffer.close();
            else if (reader != null) reader.close();
            else if (file != null) file.close();
        } catch (IOException e) {
            // report at least
            e.printStackTrace();
        }
    }
}
  • 优点:一次关闭,一次可能的异常,不需要刷新(用于输出流)
  • 缺点:仍然不优雅:空舞,必须注意 if 的顺序,无法一概而论

所以问题仍然存在。

于 2013-05-03T19:23:29.347 回答