Exceptional Java - Less than perfect exceptions hierarchy


StonesAs I said before, I am a supporter of checked exceptions in Java. I think they are a great idea that supports serious software development in the real world. I also think Java’s huge success can be attributed in part to checked exceptions. But this doesn’t mean I like everything about how the Java’s exception handling system was implemented. And there are a number of things in the exceptions class hierarchy that don’t add up in my humble opinion.

Let’s have another look at the hierarchy:

- Throwable (checked)
    - Error (unchecked)
    - Exception (checked)
        - RuntimeException (unchecked)
            - unchecked hierarchy
        - checked hierarchy

A number of weird things pop up for me:

  • Why are the top level classes instantiable? Is there any benefit in being able to create instances of Throwable, Error, Exception and RuntimeException and throw them?
  • Why are the unchecked exceptions extending checked exceptions?
  • Why there is no CheckedException class at the top of the hierarchy to clearly separate the checked and unchecked hierarchy?

These design decisions caused some of the problems people attribute to checked exceptions.
The ability to instantiate the top level classes in the hierarchy doesn’t provide any benefit other then allowing quick hacks. I have seen APIs that throw Exception instances, thus forcing the client code to catch Exception. This is one scenario where if you don’t pay attention RuntimeException instances will be swallowed in the wrong place. In order to treat them properly you have to catch them in a specific catch block and treat or re-throw them.

try
{
    ...
}
catch (Exception e)
{
    // runtime exceptions are swallowed probably without intent
}

vs.

try
{
    ...
}
catch (RuntimeException e)
{
    throw e; // avoid swallowing
}
catch (Exception e)
{
    // only checked exceptions get caught here
}

The problem of swallowed exceptions exists also due to the small design decision of deriving RuntimeException from Exception. This causes no end of grief for people who don’t take enough time to understand the effects of what they throw and what they catch.

It is clear that the compiler and the JVM know the top level exception class hierarchy by name and treat them in special ways. At the implementation level there is no marker for checked or unchecked exceptions. So it would have been easy in my opinion to keep the hierarchy clean and separate checked and unchecked exceptions. That would have avoided many problems and pain. But now it is too late so we have to deal with what exists.

Next time I will try to dig deeper into the impact checked and unchecked exceptions have on how APIs and applications are designed.

This post is part of an ongoing series:

Share this post:

These icons link to social bookmarking sites where readers can share and discover new web pages.

  • del.icio.us
  • StumbleUpon
  • Technorati
  • Digg
  • Reddit
  • Google
  • Facebook
  • description
  • Propeller
  • Slashdot

4 Responses to “Exceptional Java - Less than perfect exceptions hierarchy”

  1. Good post (even if I am no fan of checked exceptions). I completely agree, it takes a while to understand the confusing hierarchy. I often think the whole way we currently handle exceptions could need an overhaul. Have you seen the proposal by Collin Fagan?

    http://aberrantcode.blogspot.com/2008/03/try-and-try-again.html

  2. I agree, this checked and unchecked exception hierarchy leaves a lot to be desired.
    Really good point about swallowed exceptions, but it is more of a bad api design to cause such scenarios.

  3. I think Java had an unexpected level of success even for its designers. Some of the APIs and other design decisions had a bad start and then the success forced backwards compatibility decisions. I think though Java’s success was caused by:
    1. Garbage collection
    2. Checked exceptions
    3. Continuation of the C/C++ syntax

    and maybe it deserves the first place…

    4. Huge effort invested in the libraries

  4. I think that this issue is not so grave as you present it here. An Error should never be thrown by an application but by the JVM only (e.g. an OutOfMemoryError). So you should never inherit from Error anyway, neither directly from Throwable. The rule is simple: For unchecked custom exceptions, inherit from RuntimeException. For checked custom exceptions, inherit directly from Exception or one of its other subclasses.
    APIs that throw Exceptions are indeed bad, but that’s clearly an error in the API. Unfortunately there are developers who just won’t understand this (I once tried to explain it to one, but she just didn’t get it). If it causes grief to such developers then, well, may it be so.
    With well-designed APIs (yes, they do exist) these points cease to be issues.

Leave a Reply

Are you human? Type this in the box below: