While studying at university, I inevitably came across the exception and exception handling but until recently, it never really made much sense. However, I now have a clearer idea on when to use it and when not to use it. Now for a definition of what an exception is.
Definition: An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions.
With hindsight, this is an excellent definition but it can be hard to relate to when coming across this concept for the first time. A few of the questions that I should have asked myself then are:
- Why do I even need to know about exceptions?
- So what if an exception occurs?
- How do I even know that an exception has occured?
- What should I do when an exception occurs?
Yes I was indeed told that I needed to know about exceptions and exception handling (this will be explained further down) because then I would be able to terminate the application “gracefully”. However, as a novice back then, these were all pretty vacuous concepts and without a concrete example, exceptions can become very confusing and put developers off from using them and doings so in the correct manner.
The classic example given to illustrate an exception is the division by 0. This, in my opinion, is a good and bad example. It is a good example because we all know that the result of dividing a number by 0 is infinity and a computer is unable to process or even represent that. At the same time it is a bad example because further down the line, and after some reflection, we will find out that in most cases we can avoid this exception by ensuring that the divisor should not be zero before performing the division. So, it can become confusing because a great deal is made of exceptions but it would appear that in some circumstances and with sufficient thought, they can avoided. Hence, the next logical question is
Why do I even need to know about exceptions?
Even though the previous example of an exception illustrated that exceptions can be avoided if checks and data sanitisation are put into place, there are circumstances whereby no matter what safeguards are in place, exceptions might occur. This is in no way a sleight on your abilities as a developer but refer to exceptions such as trying to connect to an unavailable SQL server. Thus, exceptions are sometimes unavoidable. This brings us to the next questions.
So what if an exception occurs?How do I even know that an exception has occured?
These two questions are related and in the context of a web application, the yellow screen of death is the result of an exception occurring. As a developer, the YSOD should be avoided because
- It is not a nice user experience. The user will first of all be unable to do what he wanted to do and the YSOD techno babble is of no use to him. In this case, it is said that the application did not terminate gracefully.
- It could be a potential security risk, if this information is exposed, since it shows technical information which could be exploited.
- It decreases the end user’s faith in the application because to the end user it might indicate lack of QA.
Now that we know the consequences of an exception and why it is important to avoid it, the next question is:
What should I do when an exception occurs?
The answer to that of course is to deal with the result of an exception ,or in geek speak, we need to handle the exception. Each language has its way to that but in C#, the exception strategy is implemented through the use of the try/catch block e.g.
You would put code that might raise (fancy word for cause) exceptions in the try block. What happens behind the scenes, is that the runtime throws the exception and that exception is caught within the catch block. It is within the latter that the exception is handled i.e. dealt with. Before proceeding with exception handling and understanding the reasons behind handling an exception in a particular way, the concept of a call stack must first be explained.
This page explains the concept of a call stack in detail but it can be explained better in terms of an example. Say you have three methods A, B and C. Within method A, there is a call to method B and within method B there is a call to method C. These three methods are dependent and built or stacked upon each other to form the call stack.
Now let’s say that there is exception handling initially implemented only in method C i.e. at the bottom of the call stack. The options for error handling are thus:
- Within the catch block of method C, you can handle the exception and swallow it.
- Within the catch block of method C, you can handle the exception but throw it up.
Swallow, throw up? What? Sometimes, I wonder why people come up with such terms? These make sense only after you gain more experience but can be terribly offputting while learning about exceptions for the first time. Swallowing in this context means that after an exception occurs in method C and execution is returned to method B, the latter will not know that an exception occurred in method C. On the other hand, if the exception is thrown up by method C, method B will be notified that an exception occurred in the former. At this point, method B can either handle and swallow the exception or throw it up to method A to handle the exception.
In practical terms, the following code will swallow the exception
while the following with throw it
Now, that the code execution is within the catch block, what are you, as a developer, going to do about about it i.e. how are you going to handle the exception? In the previous section we’ve talked about swallowing and re-throwing the exception but there are other steps that can be taken to determine if you should swallow or re-throw the exception.
First, try to see if you can deal with the exception right there and then, which from experience isn’t often the case and hence why I’m struggling to come up with a concrete example at the moment. In the rare cases that you can deal with the exception then swallow it, otherwise re-throw it. However, in either case, you should log the exception and if possible provide notification to the developer of the exception so that the latter can take the appropriate measures. This is beyond the scope of this post but look into ELMAH and log4NET which serve somewhat different but sometimes overlapping functionality.
This was a brief introduction to the topic of exception and exception handling and there are plenty more resources out there but I hope that at least, this subject is making more sense. Now to recapitulate:
- Exceptions can occur and you have to have an exception handling strategy in place in order for the application to terminate gracefully.
- Although it was maybe not emphasised enough, exception handling should be the last line of “defence”. In other words, you should first make the appropriate checks to ensure that the exception doesn’t occur in the first place e.g. ensure the divisor is not 0 in a division operation. Exceptions should occur only in exceptional circumstances.