views:

4265

answers:

19

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  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
catch   // No args, so it will catch any exception
{}
reader.Close();

However, this is considered good form:

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
finally   // Will execute despite any exception
{
  reader.Close();
}

As far as I can tell, the only difference between putting cleanup code in a finally block and putting cleanup code after the try..catch blocks is if you have return statements in your try block (in that case, the cleanup code in finally will run, but code after the try..catch will not).

Otherwise, what's so special about finally?

+22  A: 

"Finally" is a statement of "Something you must always do to make sure program state is sane". As such, it's always good form to have one, if there's any possibility that exceptions may throw off the program state. The compiler also goes to great lengths to ensure that your Finally code is run.

"Catch" is a statement of "I can recover from this exception". You should only recover from exceptions you really can correct - catch without arguments says "Hey, I can recover from anything!", which is nearly always untrue.

If it were possible to recover from every exception, then it would really be a semantic quibble, about what you're declaring your intent to be. However, it's not, and almost certainly frames above yours will be better equipped to handle certain exceptions. As such, use finally, get your cleanup code run for free, but still let more knowledgeable handlers deal with the issue.

Adam Wright
+93  A: 

The big difference is that try...catch will swallow the exception, hiding the fact that an error occurred. try..finally will run your cleanup code and then the exception will keep going, to be handled by something that knows what to do with it.

Khoth
Any code written with encapsulation in mind is likely to be only able to handle the exception at the point where it is raised. Simply passing it back up the call stack in the desperate hope that something else will be able to handle some arbittary exception is a recipe for disaster.
David Arno
You're forgetting about unchecked exceptions. Pretty much any method can throw an OutOfMemoryError or something similar. You want your finally block to at least try to cleanup before exiting.
Outlaw Programmer
In most cases, it's more apparent why a particular exception would occur from the application level (e.g., a certain configuration setting) than in the class librray level.
Mark Cidade
David - I'd prefer the program to fail fast so I can be made aware of the problem rather that leave the program running in an unknown state.
Erik Forbes
If your program is in an unknown state after an exception then you're doing the code wrong.
Zan Lynx
+1 for fail fast, fortified with finally
codeulike
+1  A: 

If you don't know what exception type to catch or what to do with it, there's no point in having a catch statement. You should just leave it for a higher-up caller that may have more information about the situation to know what to do.

You should still have a finally statement in there in case there is an exception, so that you can clean up resources before that exception is thrown to the caller.

Mark Cidade
+1  A: 

From a readability perspective, it's more explicitly telling future code-readers "this stuff in here is important, it needs to be done no matter what happens." This is good.

Also, empty catch statements tend to have a certain "smell" to them. They might be a sign that developers aren't thinking through the various exceptions that can occur and how to handle them.

Ryan
+1  A: 

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.

Kibbee
+12  A: 

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.

chakrit
That's an excellent explanation!
Bob King
+1  A: 

Finally is optional -- there's no reason to have a "Finally" block if there are no resources to clean up.

Guy Starbuck
A: 

Amongst probably many reasons, exceptions are very slow to execute. You can easily cripple your execution times if this happens a lot.

+1  A: 

Taken from: here

Raising and catching exceptions should not routinely occur as part of the successful execution of a method. When developing class libraries, client code must be given the opportunity to test for an error condition before undertaking an operation that can result in an exception being raised. For example, System.IO.FileStream provides a CanRead property that can be checked prior to calling the Read method, preventing a potential exception being raised, as illustrated in the following code snippet:

Dim str As Stream = GetStream() If (str.CanRead) Then 'code to read stream End If

The decision of whether to check the state of an object prior to invoking a particular method that may raise an exception depends on the expected state of the object. If a FileStream object is created using a file path that should exist and a constructor that should return a file in read mode, checking the CanRead property is not necessary; the inability to read the FileStream would be a violation of the expected behavior of the method calls made, and an exception should be raised. In contrast, if a method is documented as returning a FileStream reference that may or may not be readable, checking the CanRead property before attempting to read data is advisable.

To illustrate the performance impact that using a "run until exception" coding technique can cause, the performance of a cast, which throws an InvalidCastException if the cast fails, is compared to the C# as operator, which returns nulls if a cast fails. The performance of the two techniques is identical for the case where the cast is valid (see Test 8.05), but for the case where the cast is invalid, and using a cast causes an exception, using a cast is 600 times slower than using the as operator (see Test 8.06). The high-performance impact of the exception-throwing technique includes the cost of allocating, throwing, and catching the exception and the cost of subsequent garbage collection of the exception object, which means the instantaneous impact of throwing an exception is not this high. As more exceptions are thrown, frequent garbage collection becomes an issue, so the overall impact of the frequent use of an exception- throwing coding technique will be similar to Test 8.05.

Scott
Scott--if the text you've quoted above is behind expertsexchange.com's paywall, you probably should not post that here. I may be wrong on this but I would bet that's not a good idea.
Onorio Catenacci
A: 

The problem with try/catch blocks that catch all exceptions is that your program is now in an indeterminate state if an unknown exception occurs. This goes completely against the fail fast rule - you don't want your program to continue if an exception occurs. The above try/catch would even catch OutOfMemoryExceptions, but that is definitely a state that your program will not run in.

Try/finally blocks allow you to execute clean up code while still failing fast. For most circumstances, you only want to catch all exceptions at the global level, so that you can log them, and then exit out.

David Mohundro
+9  A: 

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).

Mark Ingram
This is not correct. Using does not wrap the code with try/catch, it should say try/finally
pr0nin
Thanks - updated post.
Mark Ingram
+2  A: 

The try..finally block will still throw any exceptions that are raised. All finally does is ensure that the cleanup code is run before the exception is thrown.

The try..catch with an empty catch will completely consume any exception and hide the fact that it happened. The reader will be closed, but there's no telling if the correct thing happened. What if your intent was to write i to the file? In this case, you won't make it to that part of the code and myfile.txt will be empty. Do all of the downstream methods handle this properly? When you see the empty file, will you be able to correctly guess that it's empty because an exception was thrown? Better to throw the exception and let it be known that you're doing something wrong.

Another reason is the try..catch done like this is completely incorrect. What you are saying by doing this is, "No matter what happens, I can handle it." What about StackOverflowException, can you clean up after that? What about OutOfMemoryException? In general, you should only handle exceptions that you expect and know how to handle.

OwenP
A: 

Well for one, it's bad practice to catch exceptions you don't bother to handle. Check out Chapter 5 about .Net Performance from Improving .NET Application Performance and Scalability. Side note, you should probably be loading the stream inside the try block, that way, you can catch the pertinent exception if it fails. Creating the stream outside the try block defeats its purpose.

Factor Mystic
+2  A: 

Thanks everyone - I was missing the fact that with try..finally, the exception remains unhandled and bubbles up.

mbeckish
A: 

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.

Jared
Dang...I need a separate browser window open just to keep track of the answers posted WHILE I'M WRITING MINE! :)
Jared
+3  A: 

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.

Chris Lawlor
A: 

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();
}
  1. 'finally' is intention-revealing code. You declare to the compiler and to other programmers that this code needs to run no matter what.
  2. if you have multiple catch blocks and you have cleanup code, you need finally. Without finally, you would be duplicating your cleanup code in each catch block. (DRY principle)

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.

Robert Paulson
+1  A: 

There is a mistaken belief here that catch() {} is equivalent to not handling the exception. One obvious example of why this is a mistaken belief is the following:

public int robustStringToInt(string s)
{
    int res = 0;
    try
    {
        res = Int32.Parse(s);
    }
    catch() {}
    return res;
}

In the above example, my method treats an unreadable string as containing the number 0. I don't care what the exception was, if there is an exception, there is no valid number, so 0 is my result. I have handled the exception implicitly.

David Arno
You are misusing the Framework here, too. For your usage, you should use Int32.TryParse, which removes the performance hit incurred by creating the Exception in the first place.
Quantenmechaniker
I'm not misusing the framework, I was offering a contrived example to demonstrate why catch() {} can be perfectly valid way of dealing with an exception. In the real world, one would use TryParse, rather than re-inventing the wheel, but similar situations arise where there is no try method.
David Arno
A: 

try {…} catch{} is not always bad. It's not a common pattern, but I do tend to use it when I need to shutdown resources no matter what, like closing a (possibly) open sockets at the end of a thread.

mliesen