5

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.)

cucurbit
  • 1,422
  • 1
  • 13
  • 32
Mer
  • 762
  • 1
  • 6
  • 12
  • Like you, I don't see any major problems with it, other than it encouraging bad practices. – biziclop Jun 12 '14 at 10:07
  • @biziclop: I see the suppression stuff encouraging **good** practices. Previously, when dealing with an exception in logic code, we had to *throw away* exceptions resulting from cleanup code. Now we don't have to anymore (even where we can't use try-with-resources). – T.J. Crowder Jun 12 '14 at 10:27
  • 1
    @T.J. Crowder Yes, in a way. What I meant was that you had to think about the case where both the `try` and the `finally` blocks ended abruptly. If all that's "magically taken care of" then people would just ignore it. But you're right, the current solution isn't exactly watertight either so maybe auto-recording suppressed exceptions would actually improve matters. – biziclop Jun 12 '14 at 15:18

2 Answers2

6

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();
            }
        }
    }
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Ah, I didn't know they put it into JLS as well now. A bit more credibility than just oracle blogs. – Ordous Jun 12 '14 at 10:19
  • Thank you! Keeping the chain of exceptions prior to finally in a variable which can later be accessed within finally still has the feel of a workaround, but, judging from the existence of "addSuppressed()" method and the specification in the link that you provided, this seems to be the correct usage. The additional note re. how addSuppressed() is used within the implicit finally block of try-with-resources was also helpful. I'm glad that there exists a programmatic way to indicate that the ongoing Exception chain saved in an instance variable was suppressed by an exception in finally. – Mer Jun 12 '14 at 18:56
  • @Mer: Not quite following you about the "chain" of exceptions prior to finally, there's just the one (`primaryException`). I mean, you have to have a reference to the exception if you're going to add suppressed ones to it. :-) But I could imagine language features to make it prettier (other than try-with-resources, of course, which already does), like a `suppress { }` block to deal with this case. Anyway, if this answered your question, don't forget to "accept" the answer by clicking the checkmark next to it (but only if it did). – T.J. Crowder Jun 13 '14 at 06:46
2

Note the different behaviour (Using exception A for the exception in try, exception B in finally):

In a try-with-resources exception A suppresses exception B.
In a normal try exception B masks exception A.

If you want backwards compatibility (And you ALWAYS want it), you need to make B suppress A. But that is the complete opposite of what try-with-resources does (and actually, the opposite of what most developers want).

As a workaround, you can just use the (slightly modified) code that is in the Oracle blog on how try-with-resources works:

Exception ex;
try {
    doWork();
} catch (Exception e) {
    ex = e;
    throw(e);
} finally {
    try {
        doFinally();
    } catch (Exception e) {
        if (ex != null) {
            ex.addSuppressed(e);
        } else {
            throw(e);
        }
    }
}

Obviously move the throw out of the initial catch if you want the finally exception to suppress the initial one.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Ordous
  • 3,844
  • 15
  • 25