Monday, June 23, 2008

finally explained - common questions, uses, etc.


finally block - is it guaranteed to run?

Yeah... the finally block is always executed irrespective of whether the try block executes normally or throws an exception and also irrespetcive of whether the catch block (if found any) hanldes the exception normally or throws an exception itself. Whatever be the case, the finally block is always guaranteed to be executed i.e., if the control has entered a try block it's corresponding finally block will always be executed. All the uncaught exceptions are propagated after the execution of the finally block.

what if finally block throws an exception?


If the finally block itself throws an exception then all other uncaught exceptions are overruled with this exception and this exception is propagated like any other uncaught exception.

finally with control transfer statements - return or break

If the finally block doesn't have any control transfer statement then a complete execution of the finally block causes the program to proceed based on whether try block completed normally or not, catch block found or not, catch block completed normally or not, etc.

But, a finally with a control transfer statement like a return or a break will simply overrule everything and the control is transferred as specified with such a control transfer stamenet in the finally block. Find below few probable scenarios:-

  • return value of a method being overruled - suppose a non-void method has a try block (or a corresponding catch block) returning something and the associated finally block also has a return statement then the previous return value is overruled with the return value in the finally block. This can be effectively used to return a default value by overruling an uncaught exception. Though, it may not be a good idea to overrule an unchecked exception (as they are supposed to be design flaws), but we can use this feature to overrule a checked/unchecked exception in a non-void method.
  • control transfer using a labelled break - a labelled break will transfer the control accordingly overruling all the control transfer instructions pending with the try or the catch block. That means, we can simply overrule a uncaught exception (checked or unchecked both) in a void method by transferring the control by using an appropriate labelled break as well.
Using finally to nullify uncaught exceptions in Java

We can use the control transfer statements in the finally block to overrule uncaught exceptions. We need to follow two different approaches: One, for void method and Two, for non-void methods. These are:-
  • void methods - we can use a finally block with an appropriate labelled break to nullify an uncaught checked/unchecked exception raised either in the try block or in the catch block as well while handling the exception raised in the try block. Read more - Overruling uncaught exceptions in Java >>
  • non-void methods - we can use a finally block with an appropriate return statement (maybe returning a default value or any other value of the proper return type) to overrule an uncaught checked/unchecked exception(s) raised so far.
Though, we can use these two approaches to nullify unchecked exceptions as well, but we should avoid such a practice as unchecked exceptions are actually program bugs or design bugs and they should be removed.

[Update: 12-Nov-2008]: Suppose we have a 'return' statement in try (and in catch, if we have a matching catch block). Now as we know that finally gets executed before the 'return' statement (of try or catch as the case might be), but Java Specifications say that a 'return' (or any other control transfer statement for that matter) in try (or catch) is evaluated and kept in a pending state until the 'finally' block gets executed. If the Runtime System finds any 'return' (control transfer statement) in the 'finally' block then the previously kept 'return' (either of try block or of catch block) in the pending state is forgotten and the one in the 'finally' block gets executed. The pending statement is executed only if 'finally' doesn't have any control transfer statement. Refer to this article for a deeper understanding how try-catch-finally gets executed in various possible cases - programming scenarios for finally >>

Liked the article? You may like to Subscribe to this blog for regular updates. You may also like to follow the blog to manage the bookmark easily and to tell the world that you enjoy GeekExplains. You can find the 'Followers' widget in the rightmost sidebar.



Share/Save/Bookmark


4 comments:

Anonymous said...

A System.exit() call will terminate an application immediately without even running the finally clause.

Geek said...

Well... this method will not only terminate the application, but also the underlying JVM process.

Runtime.exit(int) and Runtime.halt(int) are two methods which will cause the JVM process to terminate on their invocation with the difference between the two being that the first causes the JVM Shutdown Sequence to begin whereas the latter doesn't even permit that.

A System.exit(n) simply translates into Runtime.getRuntime().exit(n) and therefore this will also start the JVM Shutdown Sequence immediately.

So, yeah you're right in saying that the System.exit() call will cause the finally block NOT to be executed because the call terminates the JVM itself so who will execute finally in such a case :-)

By any means if only the application terminates (either normally by completing the try block OR abnormally by throwing some exception in the try block OR even by throwing an exception in the catch block), then finally is guaranteed to be executed.

Thanks 'anonymous' for bringing up the point. Keep visiting/posting!

Anonymous said...

What about if we have returned some value say return i; in try block and then set the variable i=100 in finally block....
Initially i is initialized with 0..
Even in this case it is returning 0 why....?? because in any case the finally block should be executed before the return statement.

Geek said...

You're right in saying that finally gets executed before the 'return' statement, but Java Specifications say that a 'return' (or any other control transfer statement for that matter) is evaluated and kept in a pending state until 'finally' blocks gets executed. If the Runtime System finds any 'return' (control transfer statement) then the previously kept 'return' in the pending state is forgotten and the one in the 'finally' gets executed. The pending statement is executed only if 'finally' doesn't have any control transfer statement. I believe you're already aware of this.

Coming to your question, why the changed value of 'i' does not get returned? Because, the 'return' statement is already evaluated and then kept in pending state. For example: in this case 'return i' can be understood as getting translated into 'return 0' as the value of 'i' at the time of evaluation is 0 (the value of i in the try block). Once the runtime system executes the pending statement then the changed value of 'i' doesn't get reflected for the simple reason that the converted statement doesn't have any reference to 'i'. I hope this clears your doubt. Nice question, btw :-) Keep visiting/posting!