Re: java.lang Exception hierarchy - why?

From: Dan Wilkin (dwilkin_at_caci.com)
Date: 03/04/04


Date: Thu, 04 Mar 2004 10:12:24 -0500

Manav,

Thank you for your comments. I particularly appreciate the references
to the JLS in clearing this mud from the pool. Comments inline...

Manavendra Gupta wrote:
> "Dan Wilkin" <dwilkin@caci.com> wrote in message
> news:104co27571l3696@corp.supernews.com...
>
>>I have been having trouble understanding the motivation regarding the
>>inheritance hierarchy established with the top level exception classes
>>in java.lang. More specifically, I am wondering why java.lang.
>>RuntimeException (an unchecked exception) has been placed as a subclass
>>to java.lang.Exception (a checked exception)?
>
>
> Before we delve into the dicussion, lets recall the Java Exception
> hierarchy:
> Throwable
> +---Error (shouldn't catch)
> + Exception
> ++IOException
> ++FileNotFoundException
> ++... (etc)...
> + RunTimeException
> ++NullPointerException
> ++IndexOutOfBoundsException
> ++... (etc)...
>
> Note that the language defines two types of "exceptions" - recoverable
> errors, that should be handled allowing the program to terminate gracefully,
> and unrecoverable errors.
>
> The unchecked exceptions classes are the class RuntimeException and its
> subclasses, and the class Error and its subclasses. All other exception
> classes are checked exception classes
>
> Errors are not checked and are exempted from compile time checking because
> they can occur at many points in the program and recovery from them is
> difficult or impossible. A program declaring such exceptions would be
> cluttered, pointlessly(JLS, 11.2.1).

Agreed. I mistakenly recalled the placement of a memory allocation
error. As you said it is a subclass of Error. Also, I would strongly
agree that catching Errors and its subclasses would be a mistake in
programming - cluttered and pointless sums that up. Errors such as
those should have impedence placed to propagate up the stack. There
isn't much a programmer can do to resolve these and as such is generally
left up to the user to deal with (whether the user sees a stack trace or
a pretty error message is a seperate issue). So we can toss Errors and
its subclasses to the side. The issue is regarding catch blocks in
reference to unchecked and checked exceptions.

>
>
>>In this sample try/catch block I would like to catch all propagated
>>checked exceptions that have potentially been thrown, yet declared by
>>the methods doWork(), doMoreWork(), doDiffWork() -- i.e. these methods
>>have declared they will throw checked exceptions.
>
> Since your methods have declared (checked) exceptions, you clearly have a
> public contract that the callers of your methods should take into
> consideration. With exceptions, the big debate has always been whether and
> when to declare checked exceptions. This controversy is documented at:
> http://java.sun.com/docs/books/tutorial/essential/exceptions/runtime.html
>

Sure, when and where are issues truely debateable, yet not the focus of
my discussion here. But thanks for the reference to the fact.

>
>>However, I do not
>>want to catch any runtime exceptions (RuntimeException and it's
>>subclasses) - I want those to propegate to my main() and crash my
>>program (or get handled gracefully there) so that I can know that I have
>>introduced a bad programming decision into my code that is failing the
>>contract of a lower level method (e.g., passing null somewhere thus
>>instigating an IllegalArgumentException, attempting to create a very
>>large object and running out of memory, etc.).
>
> Well, this again is a contradiction in terms. You want to catch "all"
> exceptions, which means you want to catch all "recoverable" exceptions.
> RunTimeExceptions are recoverable, and hence catching an instance of
> Exception is the equivalent of stating you want to handle everything that
> has possibly gone wrong and that you can recover from.

I fail to see the contradiction. Here was my goal (quoted):

"In this sample try/catch block I would like to catch all propagated
checked exceptions"

My desire is to catch all *checked* exceptions. Or from a different
perspective, I don't want to catch any exceptions or errors except
checked exceptions - which would at the top of the class hierarchy is
java.lang.Exception. I see how you may think that this means I want to
catch *all* exceptions. Try to bear with me here. java.lang.Exception
is the super class of all checked exceptions. Unfortunately, it's also
the superclass of the supermost unchecked exception - RuntimeException.
  If I wanted to specify only one catch block to catch all *checked*
exceptions, I can't do it because by catching Exception I'll be catching
unchecked exceptions as well RuntimeException being the superclass of
all unchecked exceptions. A catch block such as this would as you say
catch all exceptions - which is not my intent.

Since an unchecked exception is not intended to always be caught - the
language should assist in enforcing this motive.

Unchecked exceptions should not be caught when the attempt is only to
catch checked exceptions. The current Java language inheritance
hierarchy prevents this by setting RuntimeException as a subclass to
Exception. This is the point of my argument. These two classes should
be swapped on the inheritance tree. Checked exceptions can continue to
inherit from Exception, and unchecked exceptions can continue to inherit
from RuntimeException.

So I would propose the following inheritance hierarchy:

Throwable
   +---- Error (certifiably unrecoverable)
          +- OutOfMemoryError
   +- RuntimeException (unchecked, unrecoverable)
       +- NullPointerException
       +- IllegalArgumentException
       +- Exception (checked, anticipate and recover)
           +- IOException
           +- FileNotFoundException

>
> FYI, the exception when "running out of memory" is not a runtime exception,
> but an Error, hence irrecoverable.
>
>
>>At this point the code
>>above would catch *all* runtime exceptions as well as the checked
>>exceptions I was anticipating!!
>
> Which is exactly what is required! If you have checked exceptions then the
> callers *know* what all could possibly go wrong and will have alternatives
> tucked into the code. It is only if something other than the possibles
> happens that you want an "umbrella" class to catch and act upon (fail
> gracefully, in most cases).
>
>
>>Can someone give me a clear explaination why the Java authors created
>>the hierarchy in this way?
>
> From the holy grail: The runtime exception classes (RuntimeException and its
> subclasses) are exempted from compile-time checking because, in the judgment
> of the designers of the Java programming language, having to declare such
> exceptions would not aid significantly in establishing the correctness of
> programs. Many of the operations and constructs of the Java programming
> language can result in runtime exceptions. The information available to a
> compiler, and the level of analysis the compiler performs, are usually not
> sufficient to establish that such run-time exceptions cannot occur, even
> though this may be obvious to the programmer. Requiring such exception
> classes to be declared would simply be an irritation to programmers.
> For example, certain code might implement a circular data structure that, by
> construction, can never involve null references; the programmer can then be
> certain that a NullPointerException cannot occur, but it would be difficult
> for a compiler to prove it. The theorem-proving technology that is needed to
> establish such global properties of data structures is beyond the scope of
> this specification (JLS, 11.2.2)
>
> In essence, almost all subclasses of Exception must be dealt with. There is
> a subclass of Exception which doesn't require handling, and that is the
> RunTimeException subclass. RunTimeException itself has subclasses, including
> ArithmeticException and NumberFormatException. RunTimeExceptions are
> normally within direct control of a Java program's code. Further, they
> normally refer to coding errors, or situations which can be directly
> rememedied with the Java code. A NullPointerException, a sublcass of
> RunTimeException, indicates that a variable has null as its value but is
> being sent a message. Fix: make sure that variable isn't null, which can be
> done directly within Java. Compare this to a FileNotFoundException, which is
> a sublcass of Exception but not of RunTimeException, and which indicates
> that the specified file does not exist. Fix: tough to say. Perhaps look
> somewhere else for the file, but likely just print out a suitable message
> and try to continue on. Files are external to Java (null variables are not),
> and are tougher to control.
>
>
>
>>Is there a JSR issue opened on this
>>particular item?
>
> Not that I know of
>
> Perhaps catching the general Exception class in this
>
>>case is poor programming practice and I should be writing catch blocks
>>for all possible checked exceptions (in which case they'd all be the
>>same - handled by my generic error handler - which in and of itself
>>stands for debate).
>
> Exactly. If you look at the source of most widely used Java-based projects
> (jakarta is a good example), in most super-classes you'd find a code-akin
> to:
>
> try {
> // do your stuff here
> } catch (typeA) {
> } catch (typeB) {
> }
> // ... all other checked types
> catch (Exception) { // something we dont know about
> }
>

Yes, traditionally, this is the desired clean approach. However, the
sample I chose was written to make a particular point.

>
>
>>Nevertheless and in short, I would prefer to see Exception a subclass of
>>RuntimeException and checked/unchecked markings would hold to their
>>original classes within the JVM and Java language
>>specification/implementation (since this is also verified at compile
>>time). In other words, RuntimeException would still be an unchecked
>>exception and all its subclasses - except for Exception which would be
>>marked as checked, all subclasses of Exception would likewise be marked
>>as checked. RuntimeException would inherit from Throwable.
>
> So all exceptions then become runtime exceptions? So a wise programmer can
> then do away with all compile-time checking and simply catch all
> RunTimeExceptions, eh? How do you then make available the information about
> most obvious errors for the compiler to check for?
>

No, not at all. Refer to my suggested revised inheritance hierarchy
(what I was suggesting previously but without the nifty tree diagram).
#1) A programmer should always be looking to catch and deal with checked
exceptions. #2) A programmer should never, by act of trying to complete
#1, be forced to handle unchecked exceptions. #3) A programmer should
be given the same flexibility in a catch block as is found in not being
required to declare unchecked exceptions in the signature of a method.
No requirement to declare unchecked exceptions - there should not be a
requirement to handle unchecked exceptions. The present inheritance
hierarchy does not support this.

> Manav
>
>



Relevant Pages

  • Re: Why shouldnt we catch class RuntimeException?
    ... A programmer should know when they err. ... the abort came from. ... These types of exceptions shouldn't occur in production code, but if they do, ... worse' (RuntimeException) happens. ...
    (comp.lang.java.programmer)
  • Re: java.lang Exception hierarchy - why?
    ... > inheritance hierarchy established with the top level exception classes ... > RuntimeException has been placed as a subclass ... The unchecked exceptions classes are the class RuntimeException and its ... > have declared they will throw checked exceptions. ...
    (comp.lang.java.programmer)
  • Re: Why shouldnt we catch class RuntimeException?
    ... are "unchecked" and pretty much always due to a programming error. ... This seems like an extremely potent argument in favor of catching and logging such exceptions. ... but what if getInput doesn't know how to show output since that is showOutput's task? ... In that case it is perfectly reasonable to have getInput throw a RuntimeException, and have doSomething catch that exception and handle it as required. ...
    (comp.lang.java.programmer)
  • Re: Why shouldnt we catch class RuntimeException?
    ... Book I’m learning from claims that exceptions of type RuntimeException ... A reasonable approach would be to have getInput just get the input, ... This is a very simple and somewhat contrived example; there are however countless reasons why RuntimeExceptions can be useful. ...
    (comp.lang.java.programmer)
  • Re: [PHP] E_RECOVERABLE_ERROR - 5.1.6 to 5.2.0
    ... why the F*** would anyone use a language that allows you to pass ... "RuntimeException" means your perfectly correct code can crash at ... true - but then it would force someone to use exceptions - the overall ...
    (php.general)