Something I wrote seven years ago. Did I learn anything in that time?
This is part of a series where I review common wisdom about Java error handling. The series is in no particular order, but the first installment explains my categorization method.
Do not use empty catch blocks
Truth: high
Importance: high
This is the most obvious of the category of exception handling rules that address how to avoid losing error information. The usual example for when you might justifiably ignore an exception goes like so:
static void closeQuietly(Closeable closeable) { // Smelly. Do not do this. try { closeable.close(); } catch (IOException e) { // I've already done what I needed, so I don't care } }
Yes, the comment makes this better than the completely empty catch block, but that is like saying that heroin is fine because you wear long sleeves.
Very rarely, suppressing an exception actually is the right thing to do, but never unless you absolutely know why it happened. Do you know when close() throws IOException? I thought not.
Do not catch and return null
Truth: medium
Importance: medium
Catching and returning null is a minor variation on the exception-suppression theme. Consider the Stooges class, which contains this method:
public String poke(String stooge) throws StoogeNotFoundException { if (stooges.contains(stooge)) { return "Woopwoopwoopwoop"; } else { throw new StoogeNotFoundException("Wise guy, eh"); } }
Suppose you want to write another method that checks a Stooge’s reaction to a poke, but Stooges gives you no isStooge method. Instead, it forces you to write this:
static String getStoogeReaction(Stooges stooges, String name) { try { return stooges.poke(name); } catch (StoogeNotFoundException e) { return null; } }
If you have to use an API that uses exceptions for flow control, something like this might be your best option, but never write an API that makes your clients do it.
Log only once
Truth: medium
Importance: low
You can also state this rule as “Log or re-throw, not both.” Redundant logging is certainly impolite to those maintaining your application, but hardly the worst you could do. You might log and re-throw for legitimate reasons:
- Your framework swallows exceptions you throw at it
- Your application logs in a specific location, different from your container
- This is part of a larger application, and you worry that your clients might ignore the exception
Do not log unless you need to, but if in doubt, log it.
Always keep the cause when chaining exceptions
Truth: high
Importance: high
Only the very naive intentionally do this, but it is easy to do accidentally, and a very easy way to lose the information about what went wrong.
In 2016, I still think exception chaining is a very important feature and I’ve been surprised by how many mainstream languages lack exception chaining.