Friday, March 01, 2024 23:34

Table of contents >> Debugging And Error Handling > Try Catch Finally

Try Catch Finally

Continuing from the last lesson, we now know that every time we deal with codes that might generate errors, we should use a Try Catch code construct. You should also know that this great construct offers one more great feature, a Finally block. This block of code is executed no matter how the execution left the Try Catch part, so this means that it will execute even when errors were thrown. This is great because, as in our previous lesson example, we might have codes that need to perform some actions when we are done with them. Specifically, lets say that we are dealing with reading or writing a file. If an exception is thrown while performing such actions, the part where we actually close the stream to the said file and release it might not get executed. In other words, that file will remain locked, thinking it is still handled by our code. We won’t be able to move, rename or delete it until we close the connection of our code to it.

That’s why, using a Finally block code, which gets executed every single time we run the Try block, we can put the codes for releasing the file inside it, ensuring that no matter what happens, we will not block it.

The basic form of a Finally block looks like this:

Of course, we can also use the exception handling parts too:

I said above that the code in a Finally block will execute every single time, regardless of anything happening in the Try or Catch blocks. Be aware though, I meant that it will execute whenever we run a Try block, not on its own. We cannot have a Finally block without a Try block attached to it. Also notice that the Finally block will not be executed if the program gets terminated from the exterior, like closing it in Task Manager.

Although we ca have multiple Catch blocks attached to a Try construct, we can only have one unique Finally block attach to a Try one.

Now, let’s take the example of reading a file from the previous lesson and analyse it a bit:

We can clearly see that the  reader.Close(); code, the one responsible for releasing the file, is on the last line of our Try block. But, what happens if we would get an error on the second line, while reading the file? Then, the execution would be transferred to the Catch block, and the line releasing the file will never be executed. We just got ourselves a file that we cannot modify, move, delete, rename, etc, until we close our program, and it gets released. Instead, let’s re-think our code, using the Finally construct:

You can see a few differences. The first one is, obviously, the fact that we added a Finally construct to our Try block. Second thing you notice is the fact that we declared the  reader before we started the Try block, outside of it. If you remember from the lesson about scope, a variable declared inside a block is visible just inside that block, and all the other blocks that are child blocks of the block where the variable is declared. So, everything inside it, nothing outside of it. Consequently, if we were to declare the variable inside the Try block, it would only be visible for the codes inside that block, and any blocks that live inside it. However, the Finally block is a completely different block, at same level with the Try one. This means that the reader variable would not be visible and recognized inside it. By declaring it outside of both the Try and the Finally blocks, it is visible inside both of them, and we can perform actions on it. Third thing to notice is that when we declared our reader variable, we also initialized it, and we initialized it as null. This is because, remember the way to initialize a reader variable is by giving it the path to a filename. But if the file does not exist, we would get an exception of type System.IO.FileNotFoundException. We don’t want to do that outside our Try block, or it will crash our program. That’s why, we declare it as null, and only initialize it inside the Try part. This also leads us to the fourth thing you should notice: inside our Finally block, we must check if the reader variable is not null, before we try to close it. This is because, what if the file does not exist? We initialized our variable as null, and if the file does not exist, we will get an exception inside the Try block, which will transfer the execution to the Catch blocks. But that will still leave our variable as null, as we initialized it first time. And we cannot perform any action on a null variable, including trying to close a reader. If we did that, we would also get an exception, and since that exception would be thrown outside a Try block, our program would still crash.


Tags: , ,

Leave a Reply

Follow the white rabbit