Rule 1. When to Catch an Exception
Catch an exception if you can solve the problem raised by the exception (e.g. by waiting for system resources, balking on a client request in an orderly fashion, interrupting a thread, logging the problem and continuing, or freeing memory).
Rule 2. When to Throw an Exception
Throw an exception with an appropriately specific type when a problem arises that you can’t solve.
Runtime exceptions are for programming errors (e.g. null pointers,index out of bounds, or illegal arguments).
Errors are for system resource errors (e.g. out of memory).
Checked exceptions are for predictable forms of application-specific errors (e.g. ill-formed input for parsers, busy network resources, or file permissions).
Corollary 3. When to Pass an Exception
Pass any exception that is raised that you don’t want to catch.
Pass the exception as-is if possible. This requires no code, but for checked exceptions, requires an appropriate try/catch block or a method/constructor declared to throw the exception.
If the exception may not be passed as is, use a try/catch to catch it and throw a new reasonably typed exception that wraps the adapted exception. That is, don’t just throw an instance of RuntimeException, which is neither an error nor specific enough for a client to catch.
September 10, 2009 at 2:16 pm |
Great post!
I tend to disagree with Rule 1. Consider, for example, a loop where a query is being issued to a different search engine in each iteration, and the results are being accumulated. In this situation, if one of the search engines doesn’t respond, you probably just want to log the error and proceed with the loop, even though the “problem raised by the exception” was not solved per se.
With respect to Rule 2, I agree on all counts except Runtime/unchecked exceptions. I think unchecked exceptions should be thrown not only for programming errors, but also for situations where the client can’t recover/proceed from the exception. An example, which I came across a few weeks ago, was an application that was required to load a great deal of resources at startup, and couldn’t proceed without any of them. The solution was to create an unchecked exception ResourceNotFoundException.
What are your thoughts on these?
September 28, 2009 at 2:32 am |
João wrote:
>I tend to disagree with Rule 1. Consider, for example, a loop where a
>query is being issued to a different search engine in each iteration, and
>the results are being accumulated. In this situation, if one of the search
>engines doesn’t respond, you probably just want to log the error and
>proceed with the loop, even though the “problem raised by the
>exception” was not solved per se.
But that IS following Rule 1! In your particular case, it is a high-level recognition of the fact that dead links and/or downed servers is a fact of life on the web, and logging the error and proceeding with the loop indeed represents an appropriate action that “solves the problem raised by the exception”.
September 10, 2009 at 3:05 pm |
I updated the post to reflect that I meant to include logging errors and continuing as a way to handle exceptions. The point is that the catcher here is doing this explicitly at an appropriate point in the loop. The wrong way to do this is to have some deeply nested component swallow an exception, then proceed until the next item either gets into an illegal state or throws a null pointer exception or whatever.
I tend to think of resources not being found as programming exceptions, though I suppose they show up in J2EE settings very much like other network errors. I often throw illegal argument exceptions if I can’t construct an object with the arguments given, but something more specific like resource-not-found exceptions would be even better.
I think you might be surprised what enterprising clients can recover from. Sometimes there are alternative lower-resource configurations available. For instance, LingPipe can trade model size for accuracy in most situations.