PUBLIC OBJECT

Catching unchecked exceptions is fragile

In my project we're having a great discussion about whether to use checked or unchecked exceptions for a particular problem. I've discovered an interesting problem with unchecked exceptions - they're not as robust with respect to refactoring and maintenance.

Here's some code that gracefully handles the unchecked exception called MappingServiceUnreachableException:

  /** 
   * @return the directions, or {@code null} if they are unavailable.
   */
  public Directions tryToLookupDirections(Address from, Address to) {
    try {
      MappingSession session = mappingService.openSession();
      MappingResponse response = session.request(
          new DirectionLookupRequest(from, to));
    } catch(MappingServiceUnreachableException e) {
      logger.log(Level.WARNING, e.getMessage(), e);
      return null;
    }
  }`</pre>The code passes all unit tests written for it. It gets checked in and gets QA testing. But a few weeks later, I discover a performance problem from not closing the session. This is an easy fix:
<pre class="prettyprint">`  /** 
   * @return the directions, or {@code null} if they are unavailable.
   */
  public Directions tryToLookupDirections(Address from, Address to) {
    MappingSession session = mappingService.openSession();
    try {
      MappingResponse response = session.request(
          new DirectionLookupRequest(from, to));
    } catch(MappingServiceUnreachableException e) {
      logger.log(Level.WARNING, e.getMessage(), e);
      return null;
    } finally {
      session.close();
    }
  }

In order to have a reference to MappingService in the finally block, I moved the call to openSession() outside of the try block. I've inadvertently changed the behaviour when that method throws!

When do find out about my mistake?

  • If MappingServiceUnreachableException was a checked exception, I'd find out about my blunder as I make it. If I'm using a good IDE, I find out before I even save the file.
  • If I have complete test coverage for the exceptional case, I'll find out about my blunder the next time that test is run - probably within a few minutes.
  • If I have only sunny-case test coverage, I won't find out about my blunder until the next time that the mapping service is unavailable.

I prefer fail-fast, so in this case checked exceptions are a no brainer. They're not perfect everywhere, but they certainly serve their purpose.