Skip to end of metadata
Go to start of metadata

There are many things to say about exception. This page is about what you should not catch, or what to do if you really must.

Never catch Throwable

There are several reasons why you should never catch Throwable:

  • Throwable covers system exceptions that you can't do anything about and should let bubble up (for instance OutOfMemoryError, ThreadDeath). Rethrowing them as a rewrapped exception hides them and doesn't help (and prevents catchers that really know how to deal with them from seeing them).
  • up to Java 6, if you catch Throwable and rethrow it you have to declare your method signature as throws Throwable which is a pain.
  • catching Throwable really means "I don't know what I catch" which is never a good sign. If you don't know then don't catch. Catching and rethrowing Exception after logging is ok but you must not rewrap the exception in a RuntimeException (because it hides InterruptedException, see below).

Never catch Exception

Catching Exception is nearly as bad as catching Throwable. Exception covers InterruptedException, which should never be caught lightly. See below.

Be careful about InterruptedException

InterruptedException is a very important mechanism in multi-threaded applications to have cooperating stopping of threads. You must never catch InterruptedException (directly or implicitly through catching Exception or Throwable) without doing some interrupt-specific job or rethrow it not rewrapped. Please read http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html which explains things in detail.

If you catch InterruptedException and do nothing about the interruption, then it's not possible to have Thread.interrupt() do its work correctly, which means you'll never be able to do proper timeouts on your threads. Having timeouts on transactions or background work is important for Nuxeo.

If in your method M you call a method P that has throws InterruptedException in its signature, then that method P has the specific semantics "this method may take some time and be blocking but can still be interrupted", therefore your own method which calls it can also take some time and be blocking and should be willing to be interrupted, and therefore your method M should also have throws InterruptedException in its signature. Never never swallow InterruptedException silently.

Specific cases

Calling something declared as throws Exception

In the rare case where you have to call a library method that's badly written and declares that it throws Exception then you should find out what the actual exception is that you're ready to deal with, let's say NumberFormatException, and let the others go by rewrapping them in RuntimeException if you don't have a more specific one declared.

You must still be careful about InterruptedException and never catch Error.

Do something like:

Rollback on exception

If you do transaction stuff, often you want to rollback when there's been an error.

But you shouldn't try to catch Exception (or even worse Throwable) just so you can rollback the transaction if there's been an error. The proper way to do it is by detecting the error without catching anything, using a flag, for instance:

If you really want to log why the rollback happened then you have to know the exception so you have to catch it, so it becomes more complex and you should deal with the Error and InterruptedException things already mentioned.

As a final note, there are still many places in Nuxeo written before we know about these good patterns, so don't be surprised to see counterexamples in Nuxeo code... In particular we behave badly about InterruptedException in many places. They should be fixed (smile)

Labels
  • None