Exceptional Series (3/3): Alternative error handling mechanism for Exceptions
Sunday, April 05, 2009 12:50 PM
Exceptions are by their very nature, very exceptional (haha pun intentional)! :> There are quite a few different ways of throwing and catching them. I hope you enjoy this short series on exception handling (this is part 3 of 3).
This is a three part Exception handling series on:
1) Throwing/catching in different ways
2) Performance impacts and
3) Alternative error handling mechanism.
This last blog in the exceptional series investigates the best way to catch exceptions in situations you can actually test for. (sample solution is available).
Alternative Error Handling Mechanisms
If you were to look at the definition of Exception you would see it's an extraordinary event/item/etc from everything else, otherwise it's included. This means an exception is something totally unexpected. If you're expecting something to happen, then by definition, it's not an exception. I have found in my past experiences a lot of developers like to use exception handling where IMHO they should be doing error checking instead.
Exceptions are meant to be used in circumstances you cannot account for. Times like when your application runs out of memory, or when someone trips over the CAT-5 cable in the server room and drops all the servers off the face of the earth, or when you just do that to your own laptop (DOH!). Or like the power outage in August 2003 in the northeast! (Oh, when that happens, you better hope you have a good UPS, but to be honest I think your app's the least of your concerns at that point. :>)
So why do developers use exceptions instead of proper error handling? I'd just be guessing, but I would say it's cause far quicker, involves less thinking, and easier to type out a try/catch statement without having to do much else afterwards. BUT! That lack of thinking at development time translates to HUGE costs at runtime, especially if you're whipping up a webapp on a server (this applies to J2EE and .NET webapps, don't be mistaken here!).
Of course, until now, this has all been a hypothesis I had in my head. I could see while debugging code in Eclipse and in Visual Studio, it always took longer to return back control to the IDE after an exception happened, but I never had any concrete proof. Until now! :) I just whipped up a sample application to illustrate the runtimes with getting the files in the Windows temp directory. In my case I emptied out my temp directory due to another problem tonight which lends well to focusing on the differences between exception handling vs error handling.
Here's the main TestingException method with the four sections of code. Section 1 is the baseline to test what happens when things run cleanly. Section 2 is doing error handling using the existing methods to check if the directory currently exists before doing anything with it. Section 3 will try to see if the directory exists but still throw the DirectoryNotFoundException. Section 4 just whips up the method call and just lets "the chips fall where they may" by doing nothing at all and just falling out of here when an exception happens.
In my past experience, I've found a lot of developers doing like Sections three and four when they are doing "exception handling". I believe they should be doing like Section two and that is the proper "error handling." OK, sometimes those types of error handling methods just aren't there in the class you're using, but did you look? Did you try to find them? I'm pretty sure most of the time, they're there.
If you're still not convinced and don't think the code is cleaner in Section 2, why don't we look at some runtimes! Below are the runtimes (in a command box, not debugging in VS) of each path through TestingException with the number of times in the loop. You start to see some patterns around 5000 times. Granted, you're not running your exception code THAT many times on an IIS box, but it still begs the question about INEFFCIENT use of resoures when you're doing exception handling instead of error handling.
||500 times (ms)
||5000 times (ms)
||50,000 times (ms)
||1, 1, 1, 1, 1
||39, 44, 40, 42, 40
||382, 383, 381, 403, 383
||3876, 3704, 3735, 3841, 3800
|Error Check But Nothing Done
||1, 1, 1, 1, 1
||37, 35, 36, 36, 51
||345, 339, 337, 362, 336
||3349, 3320, 3320, 3478, 3334
|Error Checking and Throwing Exception
||1, 1, 1, 1, 1
||71, 69, 72, 69, 70
||646, 643, 644, 678, 648
||6489, 6401, 6368, 6362, 6358
|Exception Being Thrown Only
||1, 1, 1, 1, 1
||135, 135, 144, 134, 137
||1319, 1346, 1410, 1370, 1416
||12745, 12740, 12915, 12930, 12904
Under the 5000 times column, notice how times start to double once you start dealing with exceptions? Look at the 50,000 times for Section 3 and 4! YIKES! I hope you can see in this case, error handling (Section 2) is the better way to go! It's half of the next best bet with only throwing the exception and a quarter of the time when the method throws the exception itself.
I hope this sheds some light on the differences between exception and error handling. So the next time you're looking at a try/catch block, take a moment to stop and check out the intellisense to see f there are any error handling methods available to you to use instead of just blindly catching/throwing an exception.
Now go grab a coffee and get coding! :>
Source Code: http://www.pchenry.com:8080/svn/Blog/trunk/2009/ExceptionHandlingDifferentWays
Mauro Sant'Anna: DevTeach session on Exceptions
Mauro Sant'Anna: Interview with Andres Hejlsberg (talking about not using try/catch/finally at the same time)
stackoverflow: Proper use of try...catch