views:

187

answers:

7

Hello everybody. On Tuesday I had my exam on Java at the University. While I passed the exam (:D) there is one question to which I didn't answer correctly. There was this snippet of code:

class MyExc1 extends Exception {}
class MyExc2 extends Exception {}
class MyExc3 extends MyExc2 {}

public class C1 {
    public static void main(String [] argv) throws Exception {
        try {
            System.out.print(1);
            q();

        }
        catch ( Exception i ) {
            throw( new MyExc2() );
        }
        finally {
            System.out.print(2);
            throw( new MyExc1() );
        }

    }

    static void q() throws Exception {
        try {
            throw( new MyExc1() );
        }
        catch( Exception y ) {
        }
        finally {
            System.out.print(3);
            throw( new Exception() );
        }
    }
}

and I was asked to give its output. I answered "13Exception in thread main MyExc2", but the correct answer is "132Exception in thread main MyExc1". Why is it that? I just can't understand where does MyExc2 go :S Thanks to all

A: 

I think you just have to walk the finally blocks:

  1. Print "1".
  2. finally in q print "3".
  3. finally in main print "2".
Uwe Keim
+4  A: 

Finally clause is executed even when exception is thrown from anywhere in try/catch block.

Because it's the last to be executed in the main and it throws an exception, that's the exception that the callers see.

Hence the importance of making sure that the finally clause does not throw anything, because it can swallow exceptions from the try block.

Alexander Pogrebnyak
It will also be executed EVEN if there is no exception thrown in try/catch block
nanda
+1: Direct and to the point without meandering down the entire stack which the OP already appears to understand.
R. Bemrose
A: 

Just a guess here, but the "finally" block is always executed. So, my guess is that since there is an exception thrown, in the finally block, that's the one that takes precedence.

mgroves
+7  A: 

This is what Wikipedia says about finally clause:

More common is a related clause (finally, or ensure) that is executed whether an exception occurred or not, typically to release resources acquired within the body of the exception-handling block.

Let's dissect your programme.

 try {
            System.out.print(1);
            q();

        }

So, 1 will be output into the screen, then q() is called. In q(), an exception is thrown. The exception is then caught by Exception y but it does nothing. A finally clause is then executed (it has to), so, 3 will be printed to screen. Because (in method q() there's an exception thrown in the finally clause, also q() method passes the exception to the parent stack (by the throws Exception in the method declaration) new Exception() will be thrown and caught by catch ( Exception i ), MyExc2 exception will be thrown (for now add it to the exception stack), but a finally in the main block will be executed first.

So in,

 catch ( Exception i ) {
            throw( new MyExc2() );
        }
        finally {
            System.out.print(2);
            throw( new MyExc1() );
        }

A finally clause is called...(remember, we've just caught Exception i and thrown MyExc2) in essence, 2 is printed on screen...and after the 2 is printed on screen, a MyExc1 exception is thrown. MyExc1 is handled by the public static void main(...) method.

Output:

"132Exception in thread main MyExc1"

Lecturer is correct! :-)

In essence, if you have a finally in a try/catch clause, a finally will be executed (after catching the exception before throwing the caught exception out)

The Elite Gentleman
The `catch` is executed since `q()` threw an `Exception` from its own `finally` block.
Péter Török
@Peter, yes, thanks, I didn't see that....
The Elite Gentleman
"In q(), an exception is thrown but before the exception is fully thrown, a finally clause is first executed, so, 3 will be printed to screen. " Er... no, the first exception thrown in `q` passes execution to the empty `catch` block in `q` (which swallows this exception), then to the `finally` block in `q`. Said finally block prints `3`, then throws a new exception, which thanks to `q`'s `throws Exception` is passed up the stack to the parent.
R. Bemrose
+1  A: 

A method can't throw two exceptions at the same time. It will always throw the last thrown exception, which in this case it will be always the one from the finally block.

When the first exception from method q() is thrown, it will catch'ed and then swallowed by the finally block thrown exception.

q() -> thrown new Exception -> main catch Exception -> throw new Exception -> finally throw a new exception (and the one from the catch is "lost")

Garis Suero
+1  A: 

The easiest way to think of this is imagine that there is a variable global to the entire application that is holding the current exception.

Exception currentException = null;

As each exception is thrown, "currentException" is set to that exception. When the application ends, if currentException is != null, then the runtime reports the error.

Also, the finally blocks always run before the method exits. You could then requite the code snippet to:

public class C1 {

    public static void main(String [] argv) throws Exception {
        try {
            System.out.print(1);
            q();

        }
        catch ( Exception i ) {
            // <-- currentException = Exception, as thrown by q()'s finally block
            throw( new MyExc2() ); // <-- currentException = MyExc2
        }
        finally {
             // <-- currentException = MyExc2, thrown from main()'s catch block
            System.out.print(2);
            throw( new MyExc1() ); // <-- currentException = MyExc1
        }

    }  // <-- At application exit, currentException = MyExc1, from main()'s finally block. Java now dumps that to the console.

    static void q() throws Exception {
        try {
            throw( new MyExc1() ); // <-- currentException = MyExc1
        }
        catch( Exception y ) {
           // <-- currentException = null, because the exception is caught and not rethrown
        }
        finally {
            System.out.print(3);
            throw( new Exception() ); // <-- currentException = Exception
        }
    }
}

The order in which the application executes is:

main()
{
  try
    q()
    {
      try
      catch
      finally
    }
  catch
  finally
}
rally25rs
+5  A: 

Based on reading your answer and seeing how you likely came up with it, I believe you think an "exception-in-progress" has "precedence". Keep in mind:

When an new exception is thrown in a catch block or finally block, the current exception is aborted (and forgotten) and the new exception is thrown. The new exception starts unwinding up the stack just like any other exception, aborting out of the current block (the catch or finally block) and subject to any applicable catch or finally blocks along the way.

Note that applicable catch or finally blocks includes:

When a new exception is thrown in a catch block, the new exception is still subject to that catch's finally block, if any.

Now retrace the execution remembering that, whenever you hit throw, you should abort tracing the current exception and start tracing the new exception.

Bert F
«Based on reading your answer and seeing how you likely came up with it, I believe you think an "exception-in-progress" has "precedence"» Thank you...that was exactly my thought :)
JustB