I have seen people say that it is bad form to use catch with no arguments, especially if that catch doesn\'t do anything:
StreamReader reader=new StreamRead
The effective difference between your examples is negligible as long as no exceptions are thrown.
If, however, an exception is thrown while in the 'try' clause, the first example will swallow it completely. The second example will raise the exception to the next step up the call stack, so the difference in the stated examples is that one completely obscures any exceptions (first example), and the other (second example) retains exception information for potential later handling while still executing the content in the 'finally' clause.
If, for example, you were to put code in the 'catch' clause of the first example that threw an exception (either the one that was initially raised, or a new one), the reader cleanup code would never execute. Finally executes regardless of what happens in the 'catch' clause.
So, the main difference between 'catch' and 'finally' is that the contents of the 'finally' block (with a few rare exceptions) can be considered guaranteed to execute, even in the face of an unexpected exception, while any code following a 'catch' clause (but outside a 'finally' clause) would not carry such a guaranty.
Incidentally, Stream and StreamReader both implement IDisposable, and can be wrapped in a 'using' block. 'Using' blocks are the semantic equivalent of try/finally (no 'catch'), so your example could be more tersely expressed as:
using (StreamReader reader = new StreamReader("myfile.txt"))
{
int i = 5 / 0;
}
...which will close and dispose of the StreamReader instance when it goes out of scope. Hope this helps.
With finally, you can clean up resources, even if your catch statement throws the exception up to the calling program. With your example containing the empty catch statement, there is little difference. However, if in your catch, you do some processing and throw the error, or even just don't even have a catch at all, the finally will still get run.
While the following 2 code blocks are equivalent, they are not equal.
try
{
int i = 1/0;
}
catch
{
reader.Close();
throw;
}
try
{
int i = 1/0;
}
finally
{
reader.Close();
}
finally blocks are special. The CLR recognizes and treats code withing a finally block separately from catch blocks, and the CLR goes to great lengths to guarantee that a finally block will always execute. It's not just syntactic sugar from the compiler.
Finally is executed no matter what. So, if your try block was successful it will execute, if your try block fails, it will then execute the catch block, and then the finally block.
Also, it's better to try to use the following construct:
using (StreamReader reader=new StreamReader("myfile.txt"))
{
}
As the using statement is automatically wrapped in a try / finally and the stream will be automatically closed. (You will need to put a try / catch around the using statement if you want to actually catch the exception).
Because when that one single line throws an exception, you wouldn't know it.
With the first block of code, the exception will simply be absorbed, the program will continue to execute even when the state of the program might be wrong.
With the second block, the exception will be thrown and bubbles up but the reader.Close()
is still guaranteed to run.
If an exception is not expected, then don't put a try..catch block just so, it'll be hard to debug later when the program went into a bad state and you don't have an idea why.
I agree with what seems to be the consensus here - an empty 'catch' is bad because it masks whatever exception might have occurred in the try block.
Also, from a readability standpoint, when I see a 'try' block I assume there will be a corresponding 'catch' statement. If you are only using a 'try' in order to ensure resources are de-allocated in the 'finally' block, you might consider the 'using' statement instead:
using (StreamReader reader = new StreamReader('myfile.txt'))
{
// do stuff here
} // reader.dispose() is called automatically
You can use the 'using' statement with any object that implements IDisposable. The object's dispose() method gets called automatically at the end of the block.