Excessive Exceptions
From my experience, plenty of developers are still confused about how to nicely use exceptions. I find this staggering given the mass of flame wars over the years on kosher exception use. Simply put, some people just need to be force fed - the drone community is alive and well. But, back to the big debate. When to check and when to uncheck? Given the confusion I’ve seen reign recently, it’s about time I at least started a tiny spot fire in the war.
Once upon a time I used to think this it was a clear good vs. evil battle (in that order) – no exceptions (pardon the pun). But Spring somewhat twisted my point of view. Unchecked’s are an excellent alternative for offering clients the option to handle an exception. As Spring suggests, this is especially useful in the case of fatal, unrecoverable exceptions. Remember, unchecked exceptions can be declared in throws clauses too, so clients can somewhat expect the exception by perusing the method signature. That’s something to consider, but I don’t recommend it. It is a very human process requiring too much discipline to enforce and can yield too much clutter to warrant the effort, especially in highly cohesive code with deep invocation chains, and goes against Checkstyle’s Throws Count check. As a parting word on the war of checked vs. unchecked, perhaps it draws parallels to another old war on strongly typed versus dynamic languages, with checked similar in nature to strongly typed and unchecked similar to dynamic. Some want the immediate feedback of the compiler, others consider this step more of an unnecessary burden. In the case of exceptions the burden is being forced to handle exceptions at layers that can’t do anything about it.
But the big war I’ve been fighting recently is on the number of acceptable declared exceptions per method. My preference is one per method, Checkstyle’s default. In recent times I’ve cringed at code with as much as 10 checked exceptions per method. I’m accustomed to complaining about standard JDK methods with what I consider excessive exception contracts. Reflection exceptions are a good example with one method invocation potentially causing a IllegalAccessException, IllegalArgumentException or an InvocationTargetException. I never care which exception occurred – I handle these exceptions the same way. But that’s only 3 exceptions. 10 is a completely different ball-game. The side-effects are repetitive, messy client code, confusion reigning on kosher use of the method, and nightmarish unit testing as it’s difficult to exercise all exception conditions. Indeed, this type of exception misuse has all the evils that using control flags to govern execution flow brings. As a client forced to use this code, you can pray for an alternative or write one, but that violates the Once and Only Once rule. Better is writing a proxy insulating you from the exception handling cruft. Better still is refactoring, but I find these smells emanate on the bio-hazard scale where, without a significant investment, all you are likely to achieve is scratching the surface of the code with a vein hope of someday achieving your refactoring goals.
As always, it’s best to educate and fix the problem at it’s source somewhere in the mix. So how do you argue the nuance’s of kosher exception practices with someone that doesn’t know any better? Surely key to any sound argument on this is general OO modeling best practice. Strive to create classes with very distinct responsibilities and logical methods with clear single causes of failure. Having 10 exceptions in a method is certainly possible if you’ve written an OO script thats a couple of hundred lines long. Yeah, sure it’s possible. But if that’s your way of thinking, OO is not for you and you probably should be using a language that doesn’t have the concept of an exception. Try C instead. Better still, try joining these clowns.
As an example of a nice OO approach, consider the needs of a graphics application that allows the user to draw shapes. Consider this method in the ShapeRenderer interface;
void render(Shape shape) InvalidShapeException, CircleOutOfScreenBoundsException, ShapeOutOfScreenBoundsException, IllegalShapeDimensionException, ShapeAlreadyRenderedException, UnrenderableShapeException;
vs. this method;
void render(Shape shape) throws RenderingException;
It’s blatantly obvious which one is more understandable, decoupled, and which one clients will take a liking to. A common argument I hear defending masses of exceptions is ‘I want the user to receive a different error for each exception’. Fine - there are far cleaner ways of achieving this goal. For instance centralized converter infrastructure responsible for converting failures to meaningful messages is a good example. What you use as the key to your conversion certainly does not have to be the exception class. Sure it can play a role of great importance, especially with logical exception hierarchies, but exceptions are objects that can contain any information. Use that to your advantage.
Another argument I often hear is ‘Why not just throw Exception or Throwable? That’s one exception’. Consider the side-effects; clients lose context as it communicates the method can fail for any reason and exceptions can be inadvertently gobbled. Indeed this strategy has lead to Checkstyle’s Illegal Catch check being invented.
