Resource leak while using try...finally? - java

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?
Answer
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;
}

There is technically a path for which the BufferedReader would not be closed: if reader.close() would throw an exception, because you catch the exception and do nothing with it. This can be verified by adding reader.close() again in your catch block:
} finally
{
try {
reader.close();
} catch (Exception e) {
reader.close();
}
}
Or by removing the try/catch in the finally:
} finally
{
reader.close();
}
This will make the warnings disappear.
Of course, it doesn't help you. If reader.close() is failing, then calling it again does not make sense. The thing is, the compiler is not smart enough to handle this. So the only sensible thing you can do is to add a #SuppressWarnings("resource") to the method.
Edit If you are using Java 7, what you can/should do is using try-with-resources functionality. This will get the warnings right, and makes you code simpler, saving you a finally block:
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;
}

If the BufferedReader constructor throws an exception (e.g. out of memory), you will have FileReader leaked.

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

Since close() can throw an exception (why oh why did they design it that way...) I tend to use a double try
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
try {
// do stuff with reader
} finally {
reader.close();
}
} catch(IOException e) {
// handle exceptions
}
Since this idiom eliminates the try/catch within the finally block it may be enough to keep Eclipse happy.
new BufferedReader(...) can't itself throw an IOException but technically this could still leak the FileReader if the BufferedReader constructor throws a RuntimeException or Error.

Related

Why are two try-catch blocks required for opening and reading a file?

I am trying to read a file but it is asking for two try-catch blocks, one for opening a file and another for reading its content. Why is this required?
String line = null;
try {
File file = new File("F:\\Mobile Extractor.txt");
BufferedReader reader = new BufferedReader(new FileReader(file));
while((line=reader.readLine())!=null) {
System.out.println(line);
}
reader.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Consider using finally block for avoiding memory leaks and closing the streams if you are using versions before 7. From Java 7 on wards you can use try with resources is the best practice
String line = null;
File file = new File("F:\\Mobile Extractor.txt");
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(reader!=null){
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Try-with-Resources:
String line = null;
File file = new File("F:\\Mobile Extractor.txt");
try(BufferedReader reader = new BufferedReader(new FileReader(file));) {
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
The declaration statement appears within parentheses immediately after the try keyword. The class BufferedReader, in Java SE 7 and later, implements the interface java.lang.AutoCloseable. Because the BufferedReader instance is declared in a try-with-resource statement, it will be closed regardless of whether the try statement completes normally or abruptly (as a result of the method BufferedReader.readLine throwing an IOException).
Try java8, you will not require anything. You can simply do it like this.
import java.nio.file.Files;
import java.nio.file.Paths;
Files.lines(Paths.get(path))
.filter(l -> l.contains(searchWord)).forEach(System.out::println);
The try-catch block is required for IOException.
It will check for the contents available in the file. If there are no contents, then IOException would be thrown else the contents will be displayed.
It should be like:
String line = null;
try {
File file = new File("F:\\Mobile Extractor.txt");
BufferedReader reader = new BufferedReader(new FileReader(file));
try {
while((line=reader.readLine())!=null)
{
System.out.println(line);
}
} catch(IOException ex)
{
System.out.println(ex.getMessage());
}
reader.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

Translating what an exception catches

I have a code snippet I am working on:
public void readFile()
{
BufferedReader reader = null;
BufferedReader reader2 = null;
try
{
reader = new BufferedReader(new FileReader("C:/Users/user/Desktop/testing.txt"));
reader2 = new BufferedReader(new FileReader("C:/Users/user/Desktop/testNotThere.txt"));
}
catch (FileNotFoundException e)
{
System.err.println("ERROR: FILE NOT FOUND!\n");
}
String line = null;
try {
while ((line = reader.readLine()) != null)
{
System.out.print(line);
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
And while I understand what the first exception the snippet detects: catch (FileNotFoundException e), I am looking to understand what the second exception is looking for while printing the lines of the text file:
catch (IOException e)
{
e.printStackTrace();
}
Can anyone explain what this second exception is looking for? Furthermore, how can I test to make sure this exception will be thrown in the snippet like I did with creating a second BufferedReader reader2?
IOException is thrown when your program is interrupted while reading the file.
As you may see, IO stands for "Input/Output" which means reading and writing data on disk.
So an exception of that kind means that the system crashed while while doing a reading/writing.
Source: http://docs.oracle.com/javase/7/docs/api/java/io/IOException.html

exception handling for closing reader and writer

I was just looking back over some code we wrote in a java class that I'm taking. I noticed that in the finally block there is a try/catch for closing the reader, but not the writer. I'll copy the code below. Can anyone explain why that would be? I'd like to understand better.
public class UsingFiles {
public static void main(String[] args) {
// open the input stream (from the file of this program)
BufferedReader reader = null;
PrintWriter writer = null;
try {
reader = new BufferedReader(new FileReader("./src/UsingFiles.java"));
writer = new PrintWriter("reverseFile.txt");
// String line;
// while ((line = reader.readLine()) != null) {
// System.out.println(line);
// }
// print the file in reverse order
// use recursion
reverseFile(reader, writer);
} catch (FileNotFoundException e) {
System.out.println("Couldn't open the file!");
} catch (IOException e) {
System.out.println("Problem reading the file");
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
System.out.println("Couldn't close the reader");
}
}
if (writer != null) {
writer.close();
}
}
}
private static void reverseFile(BufferedReader reader, PrintWriter writer)
throws IOException {
String line = reader.readLine();
if (line != null) {
reverseFile(reader, writer);
writer.println(line);
}
}
There are two possibilities that I can think of:
It's an oversight
Both calls to close() can throw an exception. If the first one throws an exception, the second one would be skipped - unless of course the first one was wrapped in its own try/catch block. The second one doesn't need a try/catch block since if it fails, there is no subsequent code that will be skipped
In the "real world", I would say that the answer is #1. The reason I would think #2 to be unlikely is that there is usually some other code that you will want to execute, even if you can't close some stream. This would be especially true had the catch blocks not caught an exception (or re-threw a different exception) since a fresh exception in the finally block would replace the original exception and you would never know that it had happened.
Update
As another answer has pointed out, PrintWriter.close() does not in fact throw an IOException, even though the parent interface Writer does declare that close() can throw an IOException. So that may be a better explanation.
I believe the intent was to attempt to close the writer even if the reader failed to close. If closing the reader throws an IOException, you will never execute the rest of the finally block.
This is because PrintWriter never throws exception during close(). See API. This
try {
writer.close();
} catch(IOException e) {
System.out.println("Couldn't close the writer");
}
will result in compiler error: Unreachable catch block for IOException. This exception is never thrown from the try statement body
It actually SHOULD be closed.
http://docs.oracle.com/javase/7/docs/api/java/io/PrintWriter.html
Anytime you use a resource on the system, it's great practice to close a the objects that have access to it.
There is no need to close reader in try block of finally block if you are using try with resource
try(reader = new BufferedReader(new FileReader("./src/UsingFiles.java"))
{
}
catch(Exception e)
{
}

Skip execution if exception thrown

I am stuck on something very basic. In our game we have a leveleditor/loader that can fetch levels via URL. Now if the URL points to a nonexistant file the editor should refuse to load the level and simply stay in its currentlevel, I am just struggling with the basic code.
private void loadLevel(URL url) {
Scanner in = null;
try {
in = new Scanner(new BufferedReader(new InputStreamReader(
url.openStream())));
readLine(in);
in.close();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Essentially, if FileNotFound is thrown (or any other) readLine(in) should NOT proceed. All kinds of NPE if it does.
private void loadLevel(URL url) {
Scanner in = null;
try {
in = new Scanner(new BufferedReader(new InputStreamReader(
url.openStream())));
/*if(in!=null){
readLine(in);
in.close();
}*/
readLine(in);
in.close();
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
EDIT: After #LuiggiMendoza's suggestion.
Use throws and finally. Let the calling function handle it. I haven't tested it, but this sort of thing is the idea...
private void loadLevel(URL url) throws IOException, FileNotFoundException {
Scanner in = null;
try {
in = new Scanner(new BufferedReader(new InputStreamReader(
url.openStream())));
if (in == null) throw new FileNotFoundException();
readLine(in);
}
finally {
in.close();
}
}
On the context of one single thread, if this line below throws exception, the next line of code will not execute. If you think your code is doing otherwise, it might be another thread doing it / some other code
in = new Scanner(new BufferedReader(new InputStreamReader(
url.openStream())));

Why do I need to catch a close() exception in BufferedReader but not in PrintWriter?

I have a simple file read and write function.
private void WriteToFile(String filename, String val) {
PrintWriter outStream = null;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(filename);
outStream = new PrintWriter(new OutputStreamWriter(fos));
outStream.print(val);
outStream.close();
} catch (Exception e) {
if (outStream != null) {
outStream.close();
}
}
}
private String ReadFile(String filename) {
String output = "";
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(filename);
br = new BufferedReader(fr);
output = br.readLine();
br.close();
} catch (Exception e) {
if (br != null) {
br.close();
}
}
return output;
}
When building I get:
unreported exception java.io.IOException; must be caught or declared to be thrown
br.close();
^
Why do I need to catch br.close but it doesn't complain about WriteToFile's close()?
Taken from the source code of java.io.PrintWriter:
public void close() {
try {
synchronized (lock) {
if (out == null)
return;
out.close();
out = null;
}
}
catch (IOException x) {
trouble = true;
}
}
The IOException was eaten up within the close() method in PrintWriter
From source code of java.io.BufferedReader:
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
in.close();
in = null;
cb = null;
}
}
BufferedReader throws the IOException.
That should answer your question.
Why do I need to catch br.close but it doesn't complain about WriteToFile's close()?
You can check the Java Docs for this. The close() method for BufferedReader :
public void close()
throws IOException
And the close() method for PrintWriter :
public void close()
That answer's your question as to why JVM doesn't complain. Because it is clear from the method signatures;
PrinterWriter.close() doesn't throw any Exception.
If you call fos.close(), it will ask you to catch/throw the exception.
In the PrintWriter.java. The exception is caught and handled. So you needn't catch it while using.
Java Source:
public void close() {
try {
synchronized (lock) {
if (out == null)
return;
out.close();
out = null;
}
}
catch (IOException x) {
trouble = true;
}
}
But in BufferedReader the exception is thrown. So you have to catch it when using.
Java Source:
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
in.close();
in = null;
cb = null;
}
}

Categories

Resources