Proposal: Improved Exception Handling for Java

Joseph D. Darcy Joe.Darcy at Sun.COM
Mon Mar 2 22:29:29 PST 2009


Hello.

Comments in line...

Neal Gafter wrote:
> [Resending in plain text]
>
> Improved Exception Handling for Java
>
> AUTHOR(S):
>
> Neal M Gafter
>
> OVERVIEW
>
> FEATURE SUMMARY:
>
> Catching multiple exception types: A single catch clause can now catch
> more than one exception types, enabling a series of otherwise
> identical catch clauses to be written as a single catch clause.
> Improved checking for rethrown exceptions:  Previously, rethrowing an
> exception was treated as throwing the type of the catch parameter.
> Now, when a catch parameter is declared final, rethrowing the
> exception is known statically to throw only those checked exception
> types that were thrown in the try block, are a subtype of the catch
> parameter type, and not caught in preceding catch clauses.
>
> MAJOR ADVANTAGE:
>
> Catching multiple exception types: Simplifies a commonly appearing
> pattern of redundant code.
> Improved checking for rethrown exceptions: This improvement makes it
> possible to add a try-catch statement around a block of code to
> intercept, process, and rethrow an exception without affecting the
> statically determined set of exceptions thrown from the code.
>
> MAJOR BENEFIT:
>
> Greatly simplifies writing and maintaining code where intercepting or
> processing exceptions is common.
>
> MAJOR DISADVANTAGE:
>
> One-time implementation cost for adding the features to the compiler.
> Longer language specification in describing the behavior.
>   

What sort of poor programming practices could this feature encourage or 
enable?

> ALTERNATIVES:
>
> These behaviors are approximated currently by writing a series of
> identical catch clauses.  During maintenance, the set of catch clauses
> must be modified so that it continues to match the set of exceptions
> statically thrown in the try block.  With the proposed changes, the
> catch block can be written to catch a supertype of the set of
> exceptions to be intercepted, resulting in fewer catch clauses and
> fewer changes required when the try block evolves.
>   

Another poor alternative used too often in practice is to catch a too 
general type, like Throwable, to avoid repeating more specific catch 
clauses.

> EXAMPLES
>
> SIMPLE EXAMPLE:
>
> try {
>     doWork(file);
> } catch (final IOException|SQLException ex) {
>     logger.log(ex);
>     throw ex;
> }
>
> ADVANCED EXAMPLE:
>
> Show advanced usage(s) of the feature.
>
> DETAILS
>
> SPECIFICATION:
>
> The grammar of Java is extended to allow a series of exception types,
> separated by the "OR" operator symbol, to be used in a catch clause:
>
> CatchClause:
>  catch ( CatchFormalParameter ) Block
> CatchFormalParameter:
>  VariableModifiers CatchType VariableDeclaratorId
> CatchType:
>  DisjunctionType
> DisjunctionType:
>  Type
>  Type | DisjunctionType
>
> The type system is affected as follows: For the purpose of type
> checking, a catch parameter declared with a disjunction has type
> lub(t1, t2, ...) [JLS3 15.12.2.5].

In terms of finding the members of the type, it is good existing 
concepts in the JLS can be used.

What happens if someone writes

    catch(final IOException | SomeSubclassOfIOException e) {...}

In other words, is it legal to have subclasses of a caught exception 
listed too?

>   For the purpose of exception
> checking [JLS3 11.2], a throw statement [JLS3 11.2.2] that rethrows a
> final catch parameter is treated as throwing precisely those exception
> types that
>
> the try block can throw,
> no previous catch clause handles, and
> is a subtye of one of the types in the declaration of the catch parameter
>
> To avoid the need to add support for general disjunctive types, but
> leaving open the possibility of a future extension along these lines,
> a catch parameter whose type has more than one disjunct is required to
> be declared final.
>   

I think that is a fine compromise that keep the current feature smaller 
while allowing room for a broader feature later.

Some worked examples of the sets of thrown exceptions types under 
various tricky code samples would help clarify the data flow algorithm 
for me.

> COMPILATION:
>
> A catch clause is currently compiled (before this change) to an entry
> in an exception table that specifies the type of the exception and the
> address of the code for the catch body. To generate code for this new
> construct, the compiler would generate an entry in the exception table
> for each type in the exception parameter's list of types.
>   

Interesting; so there would be no code duplication even in the class files.

> TESTING:
>
> The feature can be tested by compiling and running programs that
> exercise the feature.
>
> LIBRARY SUPPORT:
>
> No.
>
> REFLECTIVE APIS:
>
> No reflective API changes are required.
>   
> OTHER CHANGES:
>
> It would be desirable, at the same time that this change is made, to
> update the non-public Tree API that can be used with APT to express
> the syntax extension.
>   

The Tree API 
(http://java.sun.com/javase/6/docs/jdk/api/javac/tree/index.html) has a 
bit different situation than other APIs in the JDK.  The tree API is 
*not* a JCP API, but we at Sun choose to ship it and document it as part 
of Sun's JDK.  So the API is public in that sense, but it has a 
different support, stability, and compatibility contract than JCP APIs.

> MIGRATION:
>
> None required.  However, it would be easy to detect a series of
> otherwise identical catch clauses for different types and collapse
> them to a single catch clause.
>
> COMPATIBILITY
>
> BREAKING CHANGES:
>
> Joe Darcy observes that the following program compiles before this
> change, but not after:
>
> try {
>   throw new DaughterOfFoo();
> } catch (final Foo exception) {
>   try {
>      throw exception; // used to throw Foo, now throws DaughterOfFoo
>   } catch (SonOfFoo anotherException) { // Reachable?
>   }
> }
>
> However
>
> This breakage is compile-time-only; already-compiled programs continue
> to behave as before
> This kind of breakage is very unlikely to occur in practice, and
> The broken code was likely wrong before, as it attempts to catch
> exceptions that simply cannot occur.
>   

I am a bit concerned by the existence of such a program, as uncommon or 
ill-posed as it might be.

It is preferable to have a pure extension that doesn't invalidate any 
existing programs.

The platform promises JLS chapter 13 binary compatibility from release 
to release; that binary compatibility is defined to be the continued 
ability to link, nothing more.  Source compatibility is *not* promised 
from release to release, and source compatibility is not defined in the 
JLS (I take a stab at drawing out source compatibility thread levels in 
http://blogs.sun.com/darcy/entry/kinds_of_compatibility).  However, 
source compatibility should be maintained if possible.

How could the increased exception precision be maintained will still 
allow programs such as the one above to compile?

Thanks for sending this in,

-Joe

> EXISTING PROGRAMS:
>
> Except as above, none.
>
> REFERENCES
>
> EXISTING BUGS:
>
> No existing bugs that I am aware of.
>
> URL FOR PROTOTYPE (optional):
>
> An implementation of disjunctive catch parameters, but without special
> handling for final catch parameters:
>
> http://www.javac.info/
>
> See also
>
> Catching Multiple Exception Types: http://www.javac.info/Multicatch.html
> Improved Checking for Rethrown Exceptions: http://www.javac.info/Rethrown.html
>
>   




More information about the coin-dev mailing list