考虑一下:
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)
抛出UnsupportedEncodingException
,则永远不会调用buffer.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();
应该足够 - 实际上任何一个都应该足够成功 - see comments in the code by Skeet)。
包装构造函数
BufferedReader buffer = new BufferedReader(
new InputStreamReader(new FileInputStream(filename), charsetName));
基本上只是隐藏了这个问题。
请注意我使用@ TomHawtin-tackline here建议的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();
}
}
}
吗?换句话说, 关闭最里面的流 (与usually asked相反)将是more than 2时最干净的解决方案包裹的溪流? 是否有finally
装饰器也应关闭()的情况?例如,参见点here。请注意Eclipse警告:
资源泄漏:“缓冲区”永远不会关闭
Eclipse是对的吗?
这是Java 6 - Android只是Java 6我才提醒你。试图在一些实用程序类中分解IO代码,一劳永逸
答案 0 :(得分:3)
在上一个方法中,根据关闭流的规则,eclipse显示的Resource leak
警告是正确的。关闭最里面的流只关闭该流,而不是关闭该流的其他流。但关闭最外层的流是一次性操作,它将自动关闭所有底层流。
正如文章Always close streams中所述:
如果将多个流链接在一起,则关闭其中的一个 是最后一个被建造的,因此处于最高水平 抽象,将自动关闭所有底层流。所以, 一个人只需要在一个流上调用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();
}
}
答案 1 :(得分:-1)
第二种模式(检查空值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();
}
}
}
所以问题仍然存在。