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;
}
}
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: /**
* @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.