Exceptional Java - Some exceptions are more equal than others
Is there something wrong with Java exceptions? Does Java need a fundamental change in this area? Is the proposal to make all exceptions in Java runtime exceptions a solution to a real problem? What if this proposal is the solution to the wrong problem?
While reading about this conflict I started to ask myself questions like the ones above. As a result I wrote a first post meant to clarify my thoughts on the issue (Thoughts on Java Exceptions). I also tried to separate what I read on the subject from what I learned from my own experience. This is a hard thing to do since some people are very good at presenting their opinions and at persuading others.
I finished my first post with a look at the top level of the exceptions class hierarchy in Java. Exception classes are one of the two important parts of the whole exceptions system. The other is of course represented by the language features provided to throw, check for (try) and catch exceptions.
Exception hierarchy
- Throwable (checked)
- Error (unchecked)
- Exception (checked)
- checked hierarchy
- ...
- RuntimeException (unchecked)
- unchecked hierarchy
- ...
At the top of the exceptions class hierarchy sits Throwable. Every class that aspires to have its instances thrown with the throw statement has to be derived directly or indirectly from Throwable. Throwable is a checked exception and this is a very interesting fact. It actually shows what was the mindset of the language designers. The general rule is that all exceptions are checked. Unchecked exceptions are the exception. A bit unexpected Throwable can be instantiated and thrown.
Derived from Throwable we find two important classes: Error and Exception. The difference is not in the source code. Their implementations are identical. The difference is in how the Java compiler and the JVM treat them: Error is unchecked while Exception is checked.
Reasonable applications obey the javadoc
The Error hierarchy is meant to signal “serious problems that a reasonable application should not try to catch”. A glimpse into what this all means is given by the VirtualMachineError class, derived from Error. This class and its children represent errors in the JVM or situations the JVM cannot handle like “out of memory” and “stack overflow”. It was surprising for me to see how deep the Error hierarchy has grown. My feeling is this hierarchy is misused and perhaps some programmers decided to derive their class from Error instead of RuntimeException just to bypass the all too popular “catch(Exception e)“ statements. Of course I might be wrong. But for example I cannot find a reasonable explanation for java.util.zip.ZipError thrown from the bowels of java.util.zip.ZipFile. Is this a “serious problem that a reasonable application should not try to catch”?
The Exception class on the other hand signals “conditions that a reasonable application might want to catch”. Why would the reasonable application want to catch them? To make an attempt to recover and continue to run of course.
The controversy
Starting from Exception we are on the contention land. Here we find RuntimeException and its children as unchecked exceptions on one hand, and all the other exceptions as checked exceptions on the other hand. Common Java wisdom tells us to use RuntimeExceptions for programming errors, things that should not happen in a bug free program. The checked exceptions are to be used to signal situations that an application might have a chance to recover from. Of course it is extremely difficult to evaluate the chances an application has to recover from an error since for example as an API designer you might not have a clue what applications will use your API.
Unchecked exceptions are not contested by anyone. They are a standard in many programming languages and they are well accepted and understood. They can be treated at any level on the execution stack where the programmer decides, or they can be left for a default handler at thread level. the default handler usually kills the thread after printing something. Java allows you to specify the default handler if you wish - Thread.setUncaughtExceptionHandler(). Of course there is a problem with the default handler: it doesn’t handle the exception in the most appropriate context.
When the default handler is called the whole execution stack has been cleared and it is pretty difficult to know what to do with the exception. As a result, if the exceptions was born lucky, it gets logged in some file and the thread dies. But what about the situations where an exception has to be treated at some specific level - to dispose of resources for example - but the programmer was in a hurry and she forgot? The compiler didn’t warn her! Three months later the server crashes and the customer sues the company because an SLA was breached.
Exactly this kind of situation makes some people supporters of checked exceptions. With a checked exception the compiler doesn’t allow you to ignore it. Of course you can ignore it by doing nothing in the catch block. But this is a bad programming practice and can be caught at code inspections or by code analysis tools. They are also easily spotted by maintenance developers. This is the nice part about checked exceptions. The bad news is the fact that they are really hard to get right. The problem resides most of the time in the design of the APIs. There is a huge number of APIs out there that didn’t get it right. They force programmers who use them to deal with low level exceptions which are implementation details and have nothing to do with the application domain of the client code.
I will write more about what I find weird in in Java exceptions and why I still like checked exceptions in a future post. Until then don’t hide, catch thy exception!
This post is part of an ongoing series:
- 1. Exceptional Java - Thoughts on Java exceptions
- 2. Exceptional Java - Some exceptions are more equal than others
- 3. Exceptional Java - Less than perfect exceptions hierarchy
- 4. Exceptional Java - Checked exceptions are priceless… For everything else there is the RuntimeException
- 5. Exceptional Java - Design the failure case - Part 1
- 6. Exceptional Java - Design the failure case - Part 2
- 7. Exceptional Java - Exception design relativity

















