Why is try {...} finally {...} good; try {...} catch{} bad?

91,088

Solution 1

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.

Solution 2

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

Solution 3

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.

Solution 4

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

Solution 5

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.

Share:
91,088

Related videos on Youtube

mbeckish
Author by

mbeckish

Updated on September 20, 2020

Comments

  • mbeckish
    mbeckish over 3 years

    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?

    • Admin
      Admin almost 9 years
      Before you Try to Catch a tiger that you cannot handle, you should document your Finally wishes.
    • Athafoud
      Athafoud over 7 years
      Exceptions topic in documentation may give some good insights. Also take a look at the Finally Block example.
  • Onorio Catenacci
    Onorio Catenacci over 15 years
    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.
  • David Arno
    David Arno over 15 years
    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.
  • Mark Cidade
    Mark Cidade over 15 years
    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.
  • Erik Forbes
    Erik Forbes over 15 years
    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.
  • Zan Lynx
    Zan Lynx over 15 years
    If your program is in an unknown state after an exception then you're doing the code wrong.
  • pr0nin
    pr0nin over 15 years
    This is not correct. Using does not wrap the code with try/catch, it should say try/finally
  • Incognito
    Incognito about 13 years
    3 years later, this information is still hard to find. Thank you!
  • supercat
    supercat almost 11 years
    Your sentiment is widespread, but unfortunately ignores another important case: expressly invalidating an object whose invariants may no longer hold. A common pattern is for code to acquire a lock, make some changes to an object, and release the lock. If an exception occurs after making some but not all of the changes, the object may be left in an invalid state. Even though IMHO better alternatives should exist, I know of no better approach than to catch any exception that occurs while the object state may be invalid, expressly invalidate the state, and rethrow.
  • iheanyi
    iheanyi over 10 years
    @DavidArno, any code written with encapsulation in mind should only handle exception within their scope. Anything else should be passed along for someone else to handle. If I have an application that gets a file name from users then reads the file, and my file reader gets an exception opening the file, it should pass them up (or consume the exception and throw a new one) so that the application can say, hey - file didn't open, let's prompt the user for a different one. The file reader should not be able to prompt users or take any other actions in response. Its only purpose is to read files.
  • Admin
    Admin almost 9 years
    @OutlawProgrammer: you said, "You want your Finally block to at least try to clean up before exiting." Try to clean up sounds a little scary... What if the Finally block fails with an exception? (Is there a Try...Catch...Finally inside there?)
  • Jesse Williams
    Jesse Williams over 5 years
    As basic as this answer is, it's absolutely the best one. It's good to just be in the habit of try/catch/finally, even if one of the latter two is left empty. There are VERY RARE circumstances where a catch block may exist and be empty, but at least if you always write try/catch/finally, you'll see the empty block as you're perusing the code. Having an empty finally block is helpful the same way. If you need cleanup later, or need to debug a state at the time of exception, it's incredibly helpful.