I was working normally in eclipse when I got bugged by a resource leak warning in both return
values inside the try
block in this method:
@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;
}
I don't understand how it would cause resource leak since I'm declaring the reader
variable outside the try
scope, adding a resource inside the try
block and closing it in a finally
block using an other try...catch
to ignore exceptions and a NullPointerException
if reader
is null
for some reason...
From what I know, finally
blocks are always executed when leaving the try...catch
structure, so returning a value inside the try
block would still execute the finally
block before exiting the method...
This can be easily proved by:
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);
}
It result in:
calling test()
try block
finally block
test() returned b
Knowing all this, why is eclipse telling me Resource leak: 'reader' is not closed at this location
if I'm closing it in my finally
block?
I would just add to this answer that he's correct, if new BufferedReader
throws an exception, an instance of FileReader
would be open upon destruction by garbage collector because it wouldn't be assigned to any variable and the finally
block would not close it because reader
would be null
.
This is how I fixed this possible leak:
@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;
}
If the BufferedReader
constructor throws an exception (e.g. out of memory), you will have FileReader
leaked.