What’s the Best Way to Handle Exceptions?

Fri, Oct 3, 2008 (Programming)

It seems, given my limited experience, that handling exceptions depends entirely on the context in which you are developing. As a fan of “rules” that can be applied to different scenarios I wanted to hit you guys up and see what the rules-of-thumb were with regards to exception handling.

Some approaches to exception handling sort of speak for them self, for example, swallowing exceptions in an API is always wrong, you aren’t giving the caller/implementor an opportunity to handle the exception and possibly implement some intelligent work around:

try {
  // open a network connection
  // download a file
} catch(Exception e) {
  // catch everything and just eat it
}

but I could think of some scenarios (especially with regards to user-interfaces) where swallowing an exception and doing nothing with it is a perfectly valid case.

Then there is the whole Checked vs Unchecked exception issue.

As an API author the idea of Checked exceptions appeals to my technical side; if I’m writing code that could do something bad, I should force the implementor to respond to that by making them try-catch my code… I’ll leave it up to them to decide if they do something smart with it or not.

[smartads]

Unfortunately, the reality is that working with an API that uses nothing but checked exceptions is really frustrating (e.g. early versions of Hibernate) and cause your code to start looking overly complex. You might make some short-cuts by just marking your own methods as throwing those exceptions or throwing massive blocks of code into try-catch blocks just not to be bothered by it. The frustration can even be compounded when the code you are using almost always runs without a problem… you begin to doubt the need for good try-catch block semantics.

To work around this, when developing APIs, I’ve started re-throwing exceptions as Unchecked RuntimeExceptions, which my technical side hates, but my “I’m a real person and have things to get done” side likes, it lets the dev respond to potential exceptions (albeit a bit more generic) if they want to, otherwise they can ignore it:

try {
  // do something that can throw an exception
} catch(Exception e) {
  // catch all exceptions
  throw new RuntimeException("<some detailed description of what barfed>", e);
}

The idea being that by-way of the human-readable message and the wrapped exception, the caller and developer, should have enough useful information to figure out what went south.

Now with regards to application development, I find myself simply logging and eating exceptions all over the place, something along the lines of:

try {
  // do something error-ey
} catch(Exception e) {
  logger.log("<some message that will help me later>", e);
  // do nothing else
}

In some cases when I want my app to die due to an exception (or at least throw it back up a level) I’ll re-throw the exception, but that seems to be few and far between for the most part.

It’s these erratic treatments of exceptions that pushed me to finally write this all down and ask the community what they do as real developers, not as text-book writers where best-practices are always employed no matter what.

Specifically, the following scenarios:

  • As an application author, how do you catch/handle/log exceptions that occur that are non-critical? (obviously critical exceptions have to be handled, but what about the rest?)
  • As an API author, do you use Checked or Unchecked exceptions?
  • As an API author, do you rethrow exceptions or swallow them in hopes of making the API easier for the implementor?

Looking forward to feedback, suggestions, rants or just cat pictures with funny captions.

Share This on Your Favorite Social Network:
  • Facebook
  • MySpace
  • Twitter
  • Digg
  • StumbleUpon
  • LinkedIn
  • Reddit
  • FriendFeed
  • Tumblr
  • Suggest to Techmeme via Twitter
  • Technorati
  • Mixx
  • Propeller
  • Fark
  • Slashdot
  • del.icio.us
  • Google Bookmarks
  • Yahoo! Buzz
  • Print
, , ,

This post was written by:

Riyad Kalla - who has written 41 posts on kallasoft.

"Ultimately I just want to provide a resource that folks find useful."

Contact the author

10 Responses to “What’s the Best Way to Handle Exceptions?”

  1. Michael Wiles Says:

    I used to be a big fan of checked exceptions for everything, it’s what the Java API defaults to.

    I have since however, since changed to favour unchecked exceptions – but not in every case.

    Being forced to catch a myriad of exceptions when you execute a reflective method call where you can’t really do anything to recover is just irritating.

    Reply

  2. Dimitris Menounos Says:

    I always use well documented unchecked exceptions. Additionally I never try to shallow a thrown exception, instead I just wrap it and re-throw it.

    The theory is that exceptions, under normal circumstances, should not happen. If they do happen though, it should be justifiable to halt the execution flow. A good API should offer all its functionality without requiring a single try / catch around it.

    Reply

  3. Litty Joseph Says:

    Adding very informative messages at each level of exception stack is a good practice. But never dump these accumulated information on the screen of an end user – he probably could be non-friendly and exploit the knowledge of application structure. So redirect the logging to persistent stoarge (text file/database) where the ’support engineer’ could have a look when he has some time. I had bad experience of such logging IO consuming lot of time and affecting end user response time. A configurable ‘log level’ is a nice feature to incorporate…

    Reply

  4. Tracy Says:

    I like to throw RuntimeExceptions in lower-level code, but catch and wrap them at higher levels. This way, long-lived processes (like service daemons) can continue processing, but I don’t have to explicitly plan for (or think about) exceptions in most of the code. Business logic exceptions are always thrown as checked, since part of the design should be how to handle and report business logic violations. But resource exceptions (I/O errors, DB connection pool issues, etc) are always unchecked, since the whole unit of work is unable to be processed and nobody really cares how many processing layers deep it was (“I/O error in foo() -> Resource exception in bar(): I/O error in foo() -> baz(): cannot flotz: resource exception in bar(): I/O error in foo() -> … “).

    Reply

  5. Parth Barot Says:

    Very nice and informative post mates.I really liked it.

    I like to throw exceptions at the lower level and will track it in my calling code (using some DB status etc…which can be used to notify users etc.. ).Main thing is,we should log it so properly(in log and DB both if possible) that the developer/System Admin can track down the error easily while digging into the huge log file :) .Because i had been through this situation a lot more times, i know how important to track exceptions if you want to keep you app. running up.

    I mostly use checked exceptions,and mostly use diff. statuses for my business logic processes which can give me a proper indication.

    regards,
    http://www.techlads.com

    Reply

  6. Riyad Kalla Says:

    I want to thank everyone for their replies so far, they have been hugely helpful.

    @Michael/Dimitris,
    That is *exactly* what I was looking for and curious about. My gut told me that working with checked exceptions (atleast when I did it) drove me nuts, try-catching even the smallest operation was really slowing me down, because then you run into the situation where you need to decide how granular you want your try-catch and detailed handling to be and that can turn into an art-form or a nightmare just in and of itself.

    @Litty/Tracy/Parth,
    An even higher level take that I wasn’t considering but can be just as important: what to do with the exceptions. I appreciate you weighing in.

    Now I suppose a followup question would be:

    Does anyone have any favorite exception handling/logging libraries out there that fit their work flow like a glove?

    Reply

  7. Rob Whelan Says:

    I posted more detail in a blog entry (see trackback), but a few comments:

    @Michael: absolutely — the checked reflection errors are annoying because that’s pretty much guaranteed to be programmer error, and the error just needs to bubble up to the top level and be reported. I have a simple reflection utility wrapper that basically just wraps those errors in an unchecked exception with good debugging detail if something does break.

    @Litty: agreed, don’t show your user a big stack trace with all of your internal debugging info. They generally won’t get anything from that info, and it could be exploited. I generally have two error displays (talking webapps for the moment), one for development/testing (which shows all error info plus dumps the current request, session, cookies, etc. to the screen), and another for production (which just says there was an internal error that has been reported automatically, they can try again or contact technical support if it keeps happening).

    @Tracy: I agree you shouldn’t have to think about exceptions in most of the code — generally they’d indicate a coding error, and should just halt execution, because something has failed. Put in “try-finally” blocks to make sure resources get cleaned up where needed and otherwise let exceptions bubble up. But what do you mean you wrap them at higher levels? Won’t they just reach the top and get trapped/logged/handled?

    I vary in how I handle IO and database connection issues… IO in a client application probably should be checked, because actions that use IO will quite probably fail occasionally (the network is down, the file is locked by another process, etc.) and need to be handled better than just a generic error. On the server… I go back and forth. At the moment my webapps mostly have checked exceptions for database access, because they *do* get caught and wrapped (with all details of the query included) and to remind developers that resources must be cleaned up as part of error handling. That wrapper that’s rethrown could logically be unchecked, though.

    @Riyad: No special libraries; I do have a set of standard error handling code & approaches that I reuse from project to project, but it’s hard to encapsulate that kind of thing into a separate utility. I used to have custom wrapper exceptions, until the JDK added that feature. :)

    Reply

  8. Tracy Says:

    @Rob: Most of the code I write is “message handlers”, which get called several times a second. If my handler throws an exception, the whole server (process, not the machine) aborts and has to be restarted, so it’s very important that exceptions *never* “get to the top”. In most of my components, the main routine consists of a try/catch block that catches Throwable. That way, everything (even Errors) gets caught. Then I wrap that in a specific XYZHandlerException and throw that to my top-level message handler. Our exception handler base class has specific fields for disposition (log routing, notification list, severity, etc), so the message handler just takes any exceptions and passes them to an exception reporter which DTRT.

    Reply

  9. Rob Whelan Says:

    @Tracy — Ah, now I see what you’re talking about. Agreed, an error should never get to the level where the entire process aborts. I pretty much assume any program or web-app has a net for generic errors (usu. Throwable) at some high level, to handle them in a generic way.

    (Looking back at my comment, I didn’t mean “halt execution”, I mean halt execution of that transaction so the application could continue cleanly).

    So I think the pattern you’re actually using is just hiding the internal implementation of your message handler — which makes sense because the calling code has no interest in the specific implementation of each handler, so that shouldn’t be a part of that external interface.

    Curious: is your “XYZHandlerException” a checked exception?

    Reply

Trackbacks/Pingbacks

  1. An Approach to Exception Handling | Just as I had suspected - 05. Oct, 2008

    [...] response to this post, asking about guidelines different developers have come up with….  I actually started a response [...]

Leave a Reply