Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the reason for this finally clause containing close() calls

I'm studying the online java course, Introduction to programming Using Java.

In the chapter on I/O the code below is introduced with the following statement:

By the way, at the end of this program, you'll find our first useful example of a finally clause in a try statement. When the computer executes a try statement, the commands in its finally clause are guaranteed to be executed, no matter what.

The program is at the end of section 11.2.1 and is a simple program that just reads some numbers in from a file and writes them in reverse order.

The relevant code in the main method is (data is a Reader and result is a Writer):

try {
    // Read numbers from the input file, adding them to the ArrayList.        
    while ( data.eof() == false ) {  // Read until end-of-file.
        double inputNumber = data.getlnDouble();
        numbers.add( inputNumber );
    }

    // Output the numbers in reverse order.        
    for (int i = numbers.size()-1; i >= 0; i--)
        result.println(numbers.get(i));

    System.out.println("Done!");        
} catch (IOException e) {
    // Some problem reading the data from the input file.
    System.out.println("Input Error: " + e.getMessage());
} finally {
    // Finish by closing the files, whatever else may have happened.
    data.close();
    result.close();
}

So I was wondering why the finally clause was useful in this case when there are no other exit points from the try or catch clauses. Couldn't the close methods just be in the body of main instead?

I thought maybe it was because there could theoretically be some other RuntimeException which could crash the program and then leave the Reader & Writers unclosed, but then wouldn't the fact that the program had crashed close them anyway?

like image 654
mallardz Avatar asked Mar 24 '14 12:03

mallardz


People also ask

What is the purpose of the finally clause?

The finally block in java is used to put important codes such as clean up code e.g. closing the file or closing the connection. The finally block executes whether exception rise or not and whether exception handled or not. A finally contains all the crucial statements regardless of the exception occurs or not.

Why do you need to close the streams in the finally block?

The finally block is mostly used during exception handling with try and catch to close streams and files. The code in finally block is executed irrespective of whether there is an exception or not. This ensures that all the opened files are properly closed and all the running threads are properly terminated.

Why do you need the finally clause in Java?

But finally is useful for more than just exception handling — it allows the programmer to avoid having cleanup code accidentally bypassed by a return , continue , or break . Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated.

What is finally clause how it works?

finally { // Relinquish resources . . . } The finally clause is executed in all of the following cases: If all statements in the try clause completed without throwing an exception. If a return or break statement was executed in the try clause. If an exception occurred in any of the statements of the try clause.


2 Answers

Your idea is correct: The finally block will close the resources even if an unexpected exception ocurred.

You are also right that this is irrelevant if such an exception crashes the complete application, but from looking at this code you can't decide if this is the case. There might be other exception handlers, catching that exception, so it is good and correct practice to put the closing logic in a finally block.

Note that there still might be a bug hiding: if data.close() throws an exception, result.close() will never get called.

Depending on your environment there are various flavours on how to fix the bug.

  • in java 7 ff you can use try-with-resources

  • if you are using Spring, there might be a proper template similar to the JdbcTemplate

  • if nothing of those applies, yes you'll have to do a try/finally inside the finally. Quit ugly. You absolutely should at least extract this into a method as suggested in the comments.

  • conceptually cleaner but rather wordy in java pre 8 is to implement the loan pattern. If you don't happen to work with scala/clojure/haskell developers it might be more confusing then anything else.

like image 106
Jens Schauder Avatar answered Oct 21 '22 10:10

Jens Schauder


This is for a very simple reason: it is the safest way, pre Java 7 and try-with-resources, to guarantee that your resources are closed even if an exception is caught.

Consider what happened if you did instead:

try {
    // some code, then

    resource.close();
} catch (SomeException e) {
    // etc
}

If your SomeException is thrown before the resource is closed, you can leak resources. Putting the resource.close() into finally, on the other hand, guarantees that it gets closed no matter what else happens.

With Java 7 you would use this:

try (
    final InputStream in = Files.newInputStream(Paths.get("somefile"));
    // Others
) {
    // work with "in" and others
} catch (Whatever e) {
}

Your resources would then be closed before catch.


As a side note, using Java 6, the safest way to have your resources closed is to use Guava's Closer.

like image 36
fge Avatar answered Oct 21 '22 09:10

fge