Search code examples
javaexceptiontry-catch-finally

Why does Java not support retrieval of exceptions from try/catch lost when an exception is thrown from finally?


In Java 7, the feature was added to (via getSuppressed()) get exceptions thrown from the implicit finally block of a try-with-resources statement.

There still doesn't seem to be a way (that I know of) to do the opposite - when there is an explicit finally block and that throws an exception, masking the exceptions thrown and pending from the try/catch.

Why does Java not provide functionality to get these buried/lost exceptions through a mechanism similar to getSuppressed()?

It would seem that the implementation of this functionality would be similar to that used in getSuppressed() or chained exceptions, and the provided benefit would be very useful, yet it continues to be left out of each release.

What would be the danger of making these masked exceptions available to programmers through a method call similar to getSuppressed()?

(Apologies in advance if this functionality already exists and I'm just clueless.)


Solution

  • The suppression thing isn't limited to try-with-resources, and you can use it for similar situations yourself. E.g., it is provided for other situations.

    try-with-resources puts the logic for closing the resources behind the scenes, so you don't have direct access in your own code to dealing with any exceptions that occur during the process. So they added the "suppression" thing so they could use it in that behind-the-scenes code.

    But cleverly, they didn't only make it something that could be used there. You can use it yourself, via Throwable#addSuppressed.

    You can see this in the pseudo-code example given in JLS §14.20.3.1; here's a real code version of it:

    {
        SomeResource someResource = null;
        Throwable primaryException = null;
    
        try {
            someResource = /*...get the resource...*/;
            /*...do something...*/
        }
        catch (Throwable t) {
            primaryException = t;
            throw t;
        }
        finally {
            if (someResource != null) {
                if (primaryException != null) {
                    // Dealing with a primary exception, close the resource
                    // and suppress any exception resulting
                    try {
                        someResource.close();
                    }
                    catch (Throwable suppressed) {
                        primaryException.addSuppressed(suppressed);
                    }
                }
                else {
                    // Not dealing with a primary exception, close the
                    // resource without suppressing any resulting exception
                    someResource.close();
                }
            }
        }
    }