Java: try with resources vs try catch finally about order of autoclosing

Please, consider the following code:

class Bum implements AutoCloseable{

    public void bu() throws Exception{
        System.out.println("Bu");
        throw new Exception();
    }

    @Override
    public void close(){
        System.out.println("Closed");
    }
}


public class TestTryWith {
    private static void tryWith(){
        try (Bum bum=new Bum()){
            bum.bu();
        }catch (Exception ex){
            System.out.println("Exception");
            //ex.printStackTrace();
        }
    }

    private static void tryCatchFinally(){
        Bum bum=new Bum();
        try{
            bum.bu();
        }catch (Exception ex){
            System.out.println("Exception");
        }finally{
            bum.close();
        }
    }

    public static void main(String[] args) {
        tryCatchFinally();
        System.out.println("------------");
        tryWith();
    }

}

And the output is:

Bu
Exception
Closed
------------
Bu
Closed
Exception

I've read that try-with-resources is converted to try-catch-finally block by the compiler. However, as you see the order is different. When we use try-with-resources the close method is invoked BEFORE the catch clause. Why?

Jon Skeet
people
quotationmark

As ever, the answer is in the JLS - in this case, section 14.20.3.2. Basically, if you have catch or finally blocks in your try-with-resources statement, that's converted into a "normal" try/catch/finally block which contains a try-with-resources statement without your specified catch/finally block - but with the one that calls close automatically. So your try-with-resources snippet is effectively:

try {
    try (Bum bum = new Bum()) {
        bum.bu();
    }
} catch (Exception ex){
    System.out.println("Exception");
    //ex.printStackTrace();
}

Which is in turn roughly equivalent to:

try {
    Bum bum = new Bum();
    try {
        bum.bu();
    } finally {
        // It's more complicated than this...
        bum.close();
    }
} catch (Exception ex){
    System.out.println("Exception");
    //ex.printStackTrace();
}

So the "inner" finally block which closes the resource is executed before the catch block in the "outer" try statement.

people

See more on this question at Stackoverflow