Checked Exceptions are unavoidable

Les says he completely disagrees with me, but then goes on to illustrate the poor state of exception handling in many projects today, just like I did in my last post. Really, we agree more than we disagree; we just come to a different conclusion.

So what do we disagree on? Where I blame the past 7 years of exception-handling abuse on the Java specification, Les blames the developers. Where I say all this mis-use shows it was a bad decision to put them in the spec in the first place, Les thinks it was the right thing to do, and developers just need to learn to use them better.

Unfortunately, checked exceptions are part of the spec and will remain so forever (even if the engineers at Sun were to see the light, they can't take them out now for backwards compatibility reasons). So the only option we have is to learn how to use them correctly. (well, there is another option: switch to another language - but I won't go into that one right now)

I don't think wrapping every checked exception with a RuntimeException (as Bruce Eckel seems to suggest in his otherwise excellent article on checked exceptions) is the answer. Does anybody really want to use a catch-block like this: (from Bruce Eckel's article)?

catch(ExceptionAdapter ea) {
  try {
  } catch(IllegalArgumentException e) {
    // ...
  } catch(FileNotFoundException e) {
    // ...
  // etc.
When would you choose to catch an ExceptionAdapter? And how would you know which exception-classes to catch on the rethrow? Also, as I stated before, RuntimeExceptions have (potentially unwanted) side-effects when thrown from an EJB, so using them all the time is simply not an option.

So since we can't avoid them, the only solution is to learn to live with them. Most mis-use in catching exceptions comes from methods that are declared to throw exceptions the caller does not know how to handle. Minimize these by minimizing your use of checked exceptions. Instead of defaulting a new exception class to inherit from Exception, default it as a RuntimeException. Only if the following two conditions are met should you use an Exception descendant:

  • The exception is severe enough to warrant forcing all callers of this method to handle it, and
  • These callers can reasonably be expected to be able to handle this exception.
Also, you have to use a checked exception if you need to signal an error-condition from an EJB, but you don't necessarily want the transaction to be rolled back.

In all other cases, use a RuntimeException. Taking this approach will limit the number of checked exceptions that a caller is forced to handle to only those he actually can and absolutely should handle. As far as the RuntimeExceptions that your method throws are concerned: JavaDoc their existence. This allows the caller to at least know they may be thrown, which in turns allows him to catch specific ones if he so chooses.

Follow these guidelines, and watch out for the traps I mentioned in my last post, and Java's exception handling mechanism may not seem so bad anymore - you might even grow to like it.

TrackBack URL for this entry:

Checked Exceptions Are Better Than Unavoidable
Luke says that checked exceptions are unavoidable and that we should just live with it. He goes on to say that you should only use checked exceptions if "[t]he exception is severe enough to warrant forcing all callers of this method to handle it, and [...

Trackback from _mindMeld at March 2, 2003 9:16 AM

Given we have had this discussion many times, I just want to clarify one point. You are the worst kind of idiot!! I'm kidding :). I responded to you here

Posted by Les Stroud at March 2, 2003 9:18 AM

For anybody missing the "worst kind of idiot" inside joke - Les is referring to this previous post of mine

Posted by Luke Hutteman at March 2, 2003 12:27 PM

I don't see the problem with rethrowing as RuntimeException. I don't think one should code with every possible future use of his api in mind, i.e. inside an EJB, etc.

This won't sound pragmatic, but if EJB has problems (the use of "if" is intended as a small joke), it's up to 1) spec designers to solve it or 2) users to dump it. My .02

Posted by Steve Conover at March 3, 2003 12:56 PM

I agree 100% you should not code with every possible future use of your api in mind. Trying to do so will only lead to unnecessarily bloated and overly complex code. So if you don't use EJBs right now, then definitely don't worry about the transactional side-effects.

If you are using EJBs however, then those side-effects are a very important detail to consider. The EJB spec has its problems, but I don't think this is one of them. Since RuntimeExceptions can occur at any time during your transaction, it only makes sense to rollback the entire transaction when one occurs - after all, you don't know which part of the code has, and which part has not executed, so your data may very well end up in an inconsistent state if the transaction were allowed to commit. Checked exceptions on the other hand can be controlled easier as they are guaranteed to be handled, so they could potentially be recovered from well enough to still commit the transaction.

But apart from the EJB argument, the main problem I have with wrapping every exception into one generic RuntimeException-class is that you lose the ability to easily catch specific exception-classes. Just because RuntimeExceptions don't force you to catch them, doesn't mean you wouldn't want to choose to do so sometimes.

Posted by Luke Hutteman at March 3, 2003 11:02 PM

Blog Explosion! As far as I can tell, it started with this article by Bruce Eckel. Darren Hobbs responded, which caused Luke Hutteman to comment. Les Stroud disagrees, and so Luke has to answer. Now, Gosling has responded, and here...

Trackback from Infloop at September 22, 2003 10:37 AM
This discussion has been closed. If you wish to contact me about this post, you can do so by email.