我在eclipse中正常工作,当我在此方法的return
块内的try
值中的资源泄漏警告被警告时:
@Override
public boolean isValid(File file) throws IOException
{
BufferedReader reader = null;
try
{
reader = new BufferedReader(new FileReader(file));
String line;
while((line = reader.readLine()) != null)
{
line = line.trim();
if(line.isEmpty())
continue;
if(line.startsWith("#") == false)
return false;
if(line.startsWith("#MLProperties"))
return true;
}
}
finally
{
try{reader.close();}catch(Exception e){}
}
return false;
}
我不明白它会如何导致资源泄漏,因为我在reader
范围之外声明了try
变量,在try
块中添加了一个资源并将其关闭一个finally
阻止使用其他try...catch
来忽略异常,NullPointerException
如果reader
由null
出于某种原因...
据我所知,finally
块总是在离开try...catch
结构时执行,因此在try
块内返回一个值仍然会执行finally
块之前退出方法......
这可以通过以下方式轻松证明:
public static String test()
{
String x = "a";
try
{
x = "b";
System.out.println("try block");
return x;
}
finally
{
System.out.println("finally block");
}
}
public static void main(String[] args)
{
System.out.println("calling test()");
String ret = test();
System.out.println("test() returned "+ret);
}
结果是:
calling test()
try block
finally block
test() returned b
知道这一切,为什么eclipse告诉我Resource leak: 'reader' is not closed at this location
我是否在finally
区块中关闭它?
我只想添加this answer他是正确的,如果new BufferedReader
抛出异常,FileReader
的实例将在垃圾收集器销毁时打开,因为它不会被分配对于任何变量,finally
块都不会关闭它,因为reader
将为null
。
这是我修复这种可能泄漏的方法:
@Override
public boolean isValid(File file) throws IOException
{
FileReader fileReader = null;
BufferedReader reader = null;
try
{
fileReader = new FileReader(file);
reader = new BufferedReader(fileReader);
String line;
while((line = reader.readLine()) != null)
{
line = line.trim();
if(line.isEmpty())
continue;
if(line.startsWith("#") == false)
return false;
if(line.startsWith("#MLProperties"))
return true;
}
}
finally
{
try{reader.close();}catch(Exception e){
try{fileReader.close();}catch(Exception ee){}
}
}
return false;
}
答案 0 :(得分:4)
技术上有一个BufferedReader不会被关闭的路径:如果reader.close()
会抛出异常,因为你捕获了异常而对它没有任何作用。这可以通过在catch块中再次添加reader.close()
来验证:
} finally
{
try {
reader.close();
} catch (Exception e) {
reader.close();
}
}
或者删除finally中的try / catch:
} finally
{
reader.close();
}
这会使警告消失。
当然,它对你没有帮助。如果reader.close()失败,那么再次调用它是没有意义的。问题是,编译器不够智能来处理这个问题。因此,您唯一明智的做法是在方法中添加@SuppressWarnings("resource")
。
编辑如果您使用的是Java 7,您可以/应该做的是使用try-with-resources功能。这将使警告正确,并使您的代码更简单,为您节省finally
块:
public boolean isValid(File file) throws IOException
{
try(BufferedReader reader = new BufferedReader(new FileReader(file)))
{
String line;
while ((line = reader.readLine()) != null)
{
line = line.trim();
if (line.isEmpty())
continue;
if (line.startsWith("#") == false)
return false;
if (line.startsWith("#MLProperties"))
return true;
}
}
return false;
}
答案 1 :(得分:2)
如果BufferedReader
构造函数抛出异常(例如内存不足),则会FileReader
泄露。
答案 2 :(得分:1)
//If this line throws an exception, then neither the try block
//nor the finally block will execute.
//That is a good thing, since reader would be null.
BufferedReader reader = new BufferedReader(new FileReader(aFileName));
try {
//Any exception in the try block will cause the finally block to execute
String line = null;
while ( (line = reader.readLine()) != null ) {
//process the line...
}
}
finally {
//The reader object will never be null here.
//This finally is only entered after the try block is
//entered. But, it's NOT POSSIBLE to enter the try block
//with a null reader object.
reader.close();
}
答案 3 :(得分:1)
由于close()
可以抛出异常(为什么哦,为什么他们这样设计呢......)我倾向于使用双重尝试
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
try {
// do stuff with reader
} finally {
reader.close();
}
} catch(IOException e) {
// handle exceptions
}
由于这个习语消除了finally块中的try / catch,因此可能足以让Eclipse满意。
new BufferedReader(...)
本身不能抛出IOException
,但从技术上讲,如果FileReader
构造函数抛出BufferedReader
或{{1},这仍然会泄漏RuntimeException
}}