tags:

views:

305

answers:

7

Consider the following test case:

public class Main {

    static int a = 0;

    public static void main(String[] args) {
        try {
            test();
            System.out.println("---");
            test2();
        }
        catch(Exception e) {
            System.out.println(a + ": outer catch");
            a++;
        }
    }

    public static void test()
    {
        try {
            throw new Exception();
        }
        catch (Exception e) {
            System.out.println(a + ": inner catch");
            a++;
        }
        finally {
            System.out.println(a + ": finally");
            a++;
        }
    }

    public static void test2() throws Exception
    {
        try {
            throw new Exception();
        }
        finally {
            System.out.println(a + ": finally");
            a++;
        }
    }
}

With output:

0: inner catch
1: finally
---
2: finally
3: outer catch

What's the explanation for why in test() catch happens before finally while in test2() it's the other way around?

+7  A: 

Because the try block in test2() doesn't have a catch block, only a finally. The code won't "jump back" to the caller to fall into catch and then "jump ahead" to the finally to continue there as you seem to think.

BalusC
+2  A: 

Because, finally is the very last code to execute in a try..catch block, regardless of whether an exception was thrown, thrown and then handled, or not thrown at all.

In fact the only time finally will not be called is if the JVM exits before it gets to execute it, or if the thread that is executing the try code is killed or interrupted.

In response to comments: Java Description of finally

Note: If the JVM exits while the try or catch code is being executed,

then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.

However you are right that a ThreadDeath exception is thrown and I can't find much on the specifics of what seems to be conflicting information from sun. It could be a question in itself.

finally (pardon the pun) @brainimus, if you are in the finally and you throw an exception, then the finally code is being executed, my point was the conditions under which the finally code does not get executed.

Adrian Regan
I *think* that killing the thread results in a `java.lang.ThreadDeath` error being thrown, so `finally` blocks *are* executed in that case. (Interruptions are ordinary exceptions where they disrupt the execution path at all, of course.)
Donal Fellows
A finally block will also stop execution if an exception is thrown in it.
brainimus
See my updated answer...
Adrian Regan
+6  A: 

catch comes before finally in the same try-catch-finally scope.

It test2 there is no catch in the try-catch-finally scope of test2 so it does the finally before leaving the scope and falling in the higher catch.

Peter Tillemans
+4  A: 

Because the finally block is always executed right before exiting scope. The sequence of events after calling test2() is as follows:

  1. exception is thrown in test2()
  2. Since test2 has no catch block, the exception is propagated up to the caller.
  3. Since test2 has a finally block, it gets executed before returning from the method.
  4. the catch in the main method catches the exception.
Péter Török
+3  A: 

The key points are these:

  • In a try-(catch)-finally block, the finally for that particular try block is performed last
  • You can nest try blocks within another, and each of those nested try blocks can have their own finally, which would be performed last for those individual try blocks

So yes, finally is performed last, but only for the try block it's attached to.

So given the following snippet:

try {
    try {
        throw null;
    } finally {
        System.out.println("Finally (inner)");
    }
} catch (Throwable e) {
    System.out.println("Catch (outer)");
}

This prints (as seen on ideone.com):

Finally (inner)
Catch (outer)

Observe that:

  • Within (inner), Finally is last (whether or not any catch was successful)
  • Catch (outer) follows Finally (inner), but that's because Finally (inner) is nested inside another try block within (outer)

Similarly, the following snippet:

    try {
        try {
            throw null;
        } catch (Throwable e) {
            System.out.println("Catch (inner)");
        } finally {
            System.out.println("Finally (inner)");
            throw null;
        }
    } catch (Throwable e) {
        System.out.println("Catch (outer)");
    }

This prints (as seen on ideone.com):

Catch (inner)
Finally (inner)
Catch (outer)

References

Related questions

polygenelubricants
A: 

If you replace the functions by the methods' code you get:

public class Main {

    static int a = 0;

    public static void main(String[] args) {
        try {
            try {
                throw new Exception();
            }
            catch (Exception e) {
                // I catch only the *first* exception thrown   
                System.out.println(a + ": inner catch");
                a++;
                // let's go to the finally block
            }
            finally {
                System.out.println(a + ": finally");
                a++;
                // we go on
            }
            System.out.println("---");
            try {
                throw new Exception();
            }
            finally {
                // executed because at the same level
                System.out.println(a + ": finally");
                a++;
            }
        }
        catch(Exception e) {
            // I catch only the *second* exception thrown
            System.out.println(a + ": outer catch");
            a++;
        }
    }

The first exception makes the catch block execute, then the first finally block is executed. It is not visible at the outer level because of the first catch block. The second exception is intercepted by the catch block at the outer level, but the finally, located at the inner level, is executed first.

Pierre Gardin
+1  A: 

try - catch and finally are used for avoiding situations when a program may get terminated due to the occurance of unwanted error during the execution of the program.

The following points are important....

1)There is only one try for a block......any number of catch statements for a block and only one finally for a block of statments

2)finally is optional.

3) catch is also optional but if the catch statement is missing then finally must appear.

4) All catches corresponding to the child exceptions must be appearing before a catch for a parent exception..

5) Irrespective of the occurance of the exception the statements present in the finally block are executed always with one exclusion.

i.e. IF a System.out.exit() statement is encountered then the program terminates imediately hence finally can not be executed in such cases.

Note: even there is an return statement appears in try block ...then also the code in finally is executed.

Pragnesh Modh