Proposal: Improved Exception Handling for Java (original) (raw)

Neal Gafter neal at gafter.com
Thu Mar 12 11:46:07 PDT 2009


I've updated the "Improved Exception Handling" proposal. The current rich-text version can be found at http://docs.google.com/Doc?id=ddb3zt39_76dtz7bsg2

In the "Compatibility" section, I added the following:

"Because the point of the rethrow proposal is to improve the

precision of exception checking, and Java is sensitive to catch clauses that it determines to be unreachable, the most straightforward way to make this change fully compatible is to simply remove Java's requirement that catch clauses be reachable. The requirement could be eliminated or made a mandatory warning.

"It is a bit harder to support muticatch alone without either

special treatment for final catch parameters or disjunction types. The simplest way is to disallow assigning to multicatch parameters (i.e. making them implicitly final), and when they're rethrown use the types from the catch parameter's declaration as the thrown types for exception analysis. This would not be a breaking change, but would be more likely to create a breaking change later if special treatment for final catch clauses were added."

I've also added the following tutorial material to the "advanced example" section:

ADVANCED EXAMPLE: Catching Multiple Exception Types

Sometimes you need to handle one of several exception types with the same code:

try {
    return klass.newInstance();
} catch (InstantiationException e) {
    throw new AssertionError(e);
} catch (IllegalAccessException e) {
    throw new AssertionError(e);
}

One alternative is to find a common supertype of these exceptions and catch just that type:

// Broken - catches exceptions that should be allowed to propagate!
try {
    return klass.newInstance();
} catch (Exception e) {
    throw new AssertionError(e);
}

Unfortunately, that can catch more exceptions than you intend. In this example, it wraps all unchecked exceptions in AssertionError. This proposal makes it possible to catch two or more exception types in a single catch clause:

try {
    return klass.newInstance();
} catch (final InstantiationException | IllegalAccessException e) {
    throw new AssertionError(e);
}

Improved Checking for Rethrown Exceptions

Occasionally you need to intercept all exceptions, do something with them, and allow them to propogate. Doing this today is awkward. One way is to catch Throwable. But how do you rethrow it, without declaring Throwable in the current method and everything above it on the call stack?

try {
    doable.doIt();  // Specified to throw several different exceptions
} catch (Throwable ex) {
    logger.log(ex);
    throw ex;  // Won't compile unless method is specified to

throw Throwable! }

Because this code throws an expression whose dynamic type is Throwable, the compiler currently thinks that the throw statement can throw any checked exception type. Java Puzzlers describes a couple of ways of rethrowing an exception such that the compiler's exception checking is circumvented. Some folks would resort to secret sun.Misc APIs. Some programmers wrap the exception prior to rethrowing it:

try {
    doable.doIt();
} catch (Throwable ex) {
    logger.log(ex);
    throw new WrappedException(ex);  // Obscures exception type!
}

Unfortunately, this approach wraps all checked as well as unchecked exceptions. We really want the rethrown exception to be treated as if this try-finally block can only throw checked exceptions that are thrown in the try block.

If a caught exception is declared final, it is safe to rethrow any caught exception:

try {
    doable.doIt();
} catch (final Throwable ex) {
    logger.log(ex);
    throw ex;
}

Because the catch parameter is final, it can only hold exceptions that are thrown from the try block. This proposal enables exception checking to take advantage of that fact: a rethrown final catch parameter is treated as if it throws only exceptions that occur in the try block.



More information about the coin-dev mailing list