Let’s talk about the finally block for a bit, as it holds a few “getchas” in the way it works.
The Java Language Specification (amazon) specifies when the
finally block is called, and how the try block ends. In short, it means that the finally block will always occur no matter what happened in the try or any of the optional catch blocks. I will try to see how can this feature be used, touch a bit on how it is implemented by the compiler, and discuss some pitfalls this feature might bring to unexperienced programmers.
What is the finally block for?
Classically, the finally block is used to close any resources that either can’t be closed by the garbage collection (such as semaphores or resources ackquired using native code) or should be closed immediately and not wait for garbage collection to do it (such as database connections or file handlers). So, for example, one might write the following code:
Connection conn; // opened before, at the beginning of the method
try {
// execute a query
} catch (SQLException e) {
// handles the exception, dispalying a message, whatever
} finally {
conn.close();
}
This would ensure that no matter what happens, even if you return from the method in the try block, even if an exception was thrown, anything – The connection will be closed.
How does it work?
The Java Virtual Machine Specification (amazon) that a compilation of a finally statement occurs by creating a
catch block which catches all uncaught exceptions and calls the finally block as a sub-routine. Further, the try block itself is calling the finally block as well.
With my compiler I received different results, though – Either the book is outdated, or the Apple Java compiler works differently. My compiler just copies the finally block’s code to the try block’s, but leaves it uncovered in the exception table. For example, the following code, having count as a field:
try {
count = 1;
} finally {
count++;
}
Would be compiled to:
Code:
0: aload_0
1: iconst_1
2: putfield #2; //Field count:I
5: aload_0
6: dup
7: getfield #2; //Field count:I
10: iconst_1
11: iadd
12: putfield #2; //Field count:I
15: goto 31
18: astore_1
19: aload_0
20: dup
21: getfield #2; //Field count:I
24: iconst_1
25: iadd
26: putfield #2; //Field count:I
29: aload_1
30: athrow
31: return
Exception table:
from to target type
0 5 18 any
18 19 18 any
The code in lines 5-12 is identical to the code in lines 19-26, which actually translates to the count++ line. The finally block is clearly copied. Line 15 prevents the code to be called twice by jumping to the end of the method, and returning from it. The exception table at the end gives a “catch-any” protection to the try block’s code by catching any uncaught exception and jumping into the finally block if that occurs.
It might make one think that if there was an unchecked exception (division by zero, for example) right after the count++ (which would be copied as well), it would cause count to increment twice (as it would be incremented in the try block, and then in the finally block when the exception is caught). This will not happen though. If you take a look at the exception table at the end, you will notice that the copied finally block is not protected by a “catch-any” block. That would make an exception in the copied finally block to just be thrown normally, without entering the real finally block.
By the way, the code in line 18 and lines 29-30 are there to re-throw any uncaught exception in the try block that was accidently caught in the finally block.
Return values
If the finally block always occurs, which takes precedence: The return value from the try block or the one from the finally block? The answer is simple and clean: The finally block always takes precedence. This can cause some pitfalls though, if you take the following example of a method which performs some database operation and returns whether it was successful:
try {
// update the database
return true;
} catch (SQLException e) {
// rolls-back
return false;
} finally {
// closes connection
return true;
}
Now, obviously the code was intended to return false in the event of an exception. However, because of the finally block, the code will return true! I would’ve actually imagined that it would be possible to not specify a return value and then the original return value will be kept, but that’s not possible. However, as an aside, if there is a finally block you may leave unspecified return values in the try and any catch blocks.
Catch-all semantics
Since the finally block occurs no matter what happened during the try block, it’s possible that certain actions did no occur due to some NullPointerException. Since the finally block has no way of knowing it (unless you specify it using some out-of-scope variable) the finally block should not assume anything has happened since the beginning of the try block, otherwise, it might fail itself.
Well, hopefully I managed to clear some clouds over the finally statement. Let me know if there’s anything I left uncovered!
Liked Chaotic Java? It's free! But I also make some other things that aren't, which you might like. Like Firewall, a rule changing, turn based strategy game for iOS.
February 17th, 2006 at 9:29 pm
I believe around 1.4 javac stopped using jsr for short finally blocks. It’s easier for the JVM to optimise the code that way.
Apparently, the new verifier for 1.6 doesn’t handle jsr at all. There has been at least one security flaw related to jsr, and it isn’t really necessary.,
February 18th, 2006 at 1:02 am
That’s actually very interesting and sounds likely – I didn’t think Apple changed the way they compile into bytecode.
Where do I get more information to this? The best I can get is the VM spec book, but it’s certainly outdated..
January 5th, 2008 at 1:07 am
Since the finally block occurs no matter what happened during the try block…
Actually, this is not always the case.
The finally block is only executed provided you don’t call something like System.exit() in the try block. If you run such a program, you will find that the finally block is not executed.
public class Test {
public static void main(String [] args) {
try {
System.out.println(“Message 1″);
System.exit(0);
} finally {
System.out.println(“This line is not executed!”);
}
}
}
January 5th, 2008 at 9:42 am
khandes3, you’re correct. But is it a problem, considering that all (or at least most) resources are being cleared by the VM itself when it exits?
It’s true though that the ones that are not need to be released by the exit hooks, though.
January 8th, 2008 at 10:57 pm
beside being bad practice (return value in a finally block) the following snippet shows a behavior I didn’t know until shortly:
public class Test {
private static boolean aMethod() {
try {
throw new Exception();
} finally {
return true;
}
}
public static void main(String[] args) {
try {
aMethod();
System.err.println(“not catched!”);
} catch (Exception e) {
System.err.println(“catched!”);
}
}
}
To my old understanding (sorry for my ignorance) this snippet shouldn’t have compiled because an Exception is thrown without any catching nor declaration in the method signature.
1.) there’s no need for a catch if there’s a finally
But the other thing that astonished me is that the output is “not catched”. Looks like the exception is swallowed!
2.) deliberately omitting a catch is like writing an empty catch block…
or did I miss something?
January 9th, 2008 at 7:06 am
Andre:
The behavior you showed is reasonable. What happens is this:
)
When you throw an exception, the finally block is called. When the finally block finishes, the exception continues on normally, so the finally block is only for closing resources etc.
However, if you decide to return a value or throw a different exception within the finally block, that would override the exception or return value in the try block.
In your “aMethod”, your try block threw a typed exception, and was later overridden by the finally block because it returned a value. The reason the compiler didn’t request you to define the exception is because it identified that there is no chance for the exception to ever be actually thrown (the compiler is sometimes actually smart
In your main method, the value was returned (“true”) and not the exception, and therefore the “not catched” response was given. If you remove the “return true” from your finally block, and place something else (some assignment or whatever) you’d see that (a) the compiler will request that you define the exception and (b) you’d get the “catched” response.
Hope I was clear in this explanation..
January 9th, 2008 at 10:29 pm
thanks a lot for your comments! Reading it and thinking about it takes me to the opinion that it makes perfect sense. The key is
> However, if you decide to return a value or throw a different exception
> within the finally block, that would override the exception or return value
> in the try block.
any return value or exception returned within a finally block overrides any return value or exception (in all 4 permutations) a try block would return.
January 9th, 2008 at 10:46 pm
I’m happy it was made more clear for you.
Thanks again for your comments!
May 1st, 2009 at 2:19 pm
a good explanation of finally block.
August 5th, 2009 at 7:17 am
[...] as pretty, but the resources are closed at the end of it! Notice the usage of finally to ensure that the resources are closed regardless of thrown exceptions. Also notice how each close [...]
November 14th, 2009 at 5:47 pm
Great explanation of the behavior of the finally block in your comment from January 9th, 2008 at 7:06 am. I’m reading Effective Java and though it’s is great book, I wish the author had used similar plain English to explain the techniques and concepts.