Java unhandled exception disappears

Suppose there is a class such that:

public class Magic {

public static void main(String[] args){
    boolean[] val = new boolean[0];
    paradox(val);
}

private static boolean paradox(boolean[] arg) {
    Container container = null;
    try {
        container = Container.getContainer(arg[0]);
        return container.value;
    } catch (UnsupportedOperationException e) {
        e.printStackTrace();
        return false;
    } finally {
        try {
            container.sayHi();
        } catch (UnsupportedOperationException e) {
            e.printStackTrace();
        }
    }
}

private static class Container{
    private boolean value;

    private Container(boolean value){
        this.value = value;
    }

    private static Container getContainer(boolean value) throws UnsupportedOperationException{
        return new Container(value);
    }

    private void sayHi(){
        System.out.println("Hi!");
    }
}
}

If this code is executed, there is a null pointer thrown on line with

container.sayHi();

container should, in fact, be null. Before the assignment can complete there is an ArrayIndexOutOfBoundException thrown when we call getContainer(). However, what happens to the ArrayIndexOutOfBoundException? Why do we go into finally{} after an unhandled exception?

edit: poor phrasing. question is why we go directly into finally{}. And what happens to ArrayIndexOutOfBoundException

Answers


Why do we go into finally{} after an unhandled exception?

We always go to finally after a block exits (successfully, after an exception handler, or after an unhandled exception). That's exactly what finally is for: a place to put code that will be run no matter what.

However, what happens to the ArrayIndexOutOfBoundException?

If you encounter a second exception in an exception handler or a finally block, then that second exception will be propagated and the original exception will be hidden.

If you want to preserve the original exception, you can manually attach it to the new exception via Throwable#addSuppressed (or the other way around, re-throw the original exception and attach the new one as suppressed).


There is a simple rule in Java: finally is always called.1

So what happens is this:

container = Container.getContainer(arg[0]);

This throws an ArrayIndexOutOfBoundException, which is uncaught. Before the exception bubbles, finally is called.

container.sayHi();

container == null so a NullPointerException is thrown, this shadows the original exception. As per the JLS ยง14.20.2

If execution of the try block completes abruptly because of a throw of a value V, then there is a choice

... then

If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and the throw of value V is discarded and forgotten).

emphasis mine

1: except when System.exit is called or some other rare cirumstances.


Another surprise you may get when doing control flow operations inside finally block :

public static void main(String[] args) {
    System.out.println(badFunction());
}

private static String badFunction() {
    try {
        throw new RuntimeException("Catch it!");
    } finally {
        return "Exception disappears";
    }
}

Need Your Help

What is better to use for automatic return types: decltype or std::common_type<>::type (if possible)?

c++ c++11 typetraits decltype

As answer to my last question it was suggested to use, when possible, std::common_type&lt;X,Y&gt;::type in the declaration of automatic return types instead of my original decltype(). However, doin...

Uploadify gives error HTTP Error (302) in yii

php ajax session yii uploadify

Yesterday I integrated uploadify in a Yii application and it worked good. But suddenly I found that it does not work rather showing error HTTP Error (302). I found this is happened only firefox, IE...