The Bad Practices of Exception Handling
Exception handling has truly been a blessing to us software developers. Without it, dealing with special conditions and writing robust programs was a lot more painful. But, like any powerful tool, badly used it could cause more harm than good. This article name the top three on my Exception handling bad practices list, all of which I’ve been practicing in the past but now stay away from.
Swallowing Exceptions
Have you ever come across code like this?
try
{
DoSomeNonCriticalStuff();
}
catch (Exception e)
{
// Ignore errors
}
DoStuffThatMustBeDoneDispiteAnyErrorsAbove();
Of all the bad exception handling practices, this is the worst since its effect is the complete opposite of the programmer’s intention. The reasoning goes something like this: Catching exceptions where they don’t hurt makes my program more robust since it’ll continue working even when conditions aren’t perfect.
The reasoning could have been valid if it wasn’t for Fatal exceptions; Here described by Eric Lippert.
Fatal exceptions are not your fault, you cannot prevent them, and you cannot sensibly clean up from them. They almost always happen because the process is deeply diseased and is about to be put out of its misery. Out of memory, thread aborted, and so on. There is absolutely no point in catching these because nothing your puny user code can do will fix the problem. Just let your “finally” blocks run and hope for the best.
Catching and ignoring these fatal exceptions makes your program less robust since it will try to carry on as if nothing happened in the worst of conditions, most likely making things worse. Not very Fail fastish.
So, am I saying that ignoring exceptions is bad and should always be avoided? No, the bad practice is catching and ignoring general exceptions. Specific exceptions on the other hand is quite OK.
try
{
DoSomeNonCriticalStuff();
}
catch (FileNotFoundException e)
{
// So we couldn't find the settings file, big deal!
}
Bad example, I know, but you get the point.
Throwing Exception
Here’s another bad practice I come across every now and then.
throw new Exception("No connection!");
The problem is that in order to handle Exception we have to catch Exception, and if we catch Exception we have to be prepared to handle every other type of Exception, including the Fatal exceptions that we discussed in the previous section.
So, if you feel the need to throw an exception, make sure it’s specific.
throw new NoConnectionException();
If the idea of defining lots of specific exceptions puts you off, then the very least thing you should do is to define your own application exception to use instead of the basic Exception. This is nothing I recommend though, since general exceptions, like ApplicationException, violate the Be specific rule of the Three rules for Effective Exception Handling. It’ll make you depend heavily on the message property to separate different errors, so don’t go there.
Overusing exceptions
Exceptions is a language construct to handle exceptional circumstances, situations where a piece of code discovers an error but don’t have the context necessary to handle it. It should not be used to handle valid program states. The reasons are:
- Performance. Throwing an exception with all that’s involved, like building a stack trace, will cost you a second or so.
- Annoyance. Debugging code where exceptions are a part of the normal execution flow can be frustrating.
Eric Lippert calls those exceptions Vexing exceptions, which I concider a great name given the second argument. Make sure you’ll check out his article (link at the beginning of this article).
…
Those were the three misuses of exception handling I concider worst. What’s on your list?
Cheers