What is the purpose of “finally” in try/catch/fina

2019-02-03 05:20发布

问题:

The syntax will change from language to language, but this is a general question.

What is the difference between this....

try
{
     Console.WriteLine("Executing the try statement.");
     throw new NullReferenceException();
}
catch (NullReferenceException e)
{
     Console.WriteLine("{0} Caught exception #1.", e);
}       
finally
{
     Console.WriteLine("Executing finally block.");
}

and this....

try
{
    Console.WriteLine("Executing the try statement.");
    throw new NullReferenceException();
}
catch (NullReferenceException e)
{
    Console.WriteLine("{0} Caught exception #1.", e);
}        
Console.WriteLine("Executing finally block.");

I keep seeing it being used, so I assume there's a good reason to use finally, but I can't figure out how it's any different from just putting code after the statement since it will still run.

Is there ever a scenario where finally doesn't run?

回答1:

In your example, it doesn't make a whole lot of difference.

Picture this, though:

    try
    {
        Console.WriteLine("Executing the try statement.");
        throw new NullReferenceException();
    }
    catch (SomeOtherException e)
    {
        Console.WriteLine("{0} Caught exception #1.", e);
    }       
    finally
    {
        Console.WriteLine("Executing finally block.");
    }

    Console.WriteLine("Executing stuff after try/catch/finally.");

In this case, the catch won't catch the error, so anything after the whole try/catch/finally will never be reached. However, the finally block will still run.



回答2:

try
{
    throw new Exception("Error!");
}
catch (Exception ex)
{
    throw new Exception(ex, "Rethrowing!");
}
finally
{
    // Will still run even through the catch kicked us out of the procedure
}

Console.WriteLine("Doesn't execute anymore because catch threw exception");


回答3:

It really depends - some other answers have very good reasons to use a Finally block. But I think the best reason is because you're doing exception handling. Things you do in a Finally block typically involve cleaning up resources to ensure proper continuation, regardless of whether or not an exception was thrown - to me that's still part of the exception handling, at least part of a "try something" operation.

IMHO the Finally scope highlights the fact that its code contains stuff that deserves special attention in case of an exception.



回答4:

finally block is guaranted to be excuted. So, in your example, results of both cases are looks same. but if you use return or throw in your catch block, you can see what is difference.



回答5:

Finally should be used to everything that needs to be done in order to keep a system consistent. This usually means release resources

Finally is always executed, no matter what exception was thrown. It should be used to release resources, in the following cases:

  • Finalize a connection
  • Close a file handler
  • Free memory
  • Close a database connection

Let me give a complete example. Imagine that that you are sending messages through the network. In pseudo-code:

// With finally                  |  //Without finally
try{                             |  try{  
  send_message()                 |    send_message() 
} catch(NetworkError){           |  } catch(NetworkError){ 
  deal_with_exception()          |    deal_with_exception()
} finally {                      |  }
  finalizes_connection()         |  finalizes_connection() 
}                                |

The only difference of both codes is when what is hold in the try block raises an exception that is not NetworkError, for example, MethodNotFound. In the first case, the method finalizes_connection() will be called, and in the second one, it will not.

A connection is naturally done through more than one program. So what happens in the case of a MethodNotFound exception to the other program? In the first case, your program will finish the connection and the other program and it will be happy. In the second case, the other program can be waiting for your response forever. What if the other program can only receive one connection per time? You just bugged the other program as well.

This would also apply for a file, for example, that you opened and other programs wouldn't be able to open for reading (in Windows). And for memory, it is never released and now you have a memory leak.



回答6:

finally runs for both try and catch. It ensures that it will run, but it is not 100% guaranteed it will [some errors stop execution of code]



回答7:

try block needs at least one catch or a finally.after executing all catch blocks the finally block will be executed.You can add any logic you need there which should be done ultimately.



回答8:

Its a good practice to use finally to handle program crashes. finally will always run .If the function exits inside of the try catch block, or another error is thrown in either the try or the catch, the finally will still execute. You won't get that functionality not using the finally statement.



回答9:

I don't know C#, but the purpose of a finally block in Java-ish languages is to ensure that system resources are relinquished, especially if garbage collection is irregular. It's the same principle for all. Consider the block

InputStream is = new FileInputStream("foo.txt");
OutputStream os = new FileOutputStream("D:/nonexistent/directory/bar.txt");
// Throws a FileNotFoundException.

The variable is is created successfully, and takes up system resources. Processes can only use a fixed number of file handles at a time. The variable os is never created, and an exception is thrown, and bubbles up to the caller. In the process, is goes out of scope, and becomes eligible for garbage collection.

However garbage collections are never guaranteed to happen, or they may happen at some indefinite time in the future. So, the system resources taken by is may never be freed. This can be costly, or can crash the program if it happens enough times. So, finally blocks were put into Java. Other languages have similar constructs. In C++, destructors are invoked deterministically. LISPy languages have unwind-protect, but those are usually packaged in with-foo macros.

In Java 6 and lower, one would do this:

try {
    is = new FileInputStream("foo.txt");
    os = new FileOutputStream("D:/nonexistent/directory/bar.txt");
    // work...
} finally {
    if (is != null) {
        try {
            is.close();
        } catch (IOException ignored) {}
    }
    if (os != null) {
        try {
            os.close();
        } catch (IOException ignored) {}
    } 
}

You can't just call is.close() because that might throw, and then os will never be closed. You have to check for null too. Sane people used Jakarta Commons-IO's IOUtils.closeQuietly() methods to replace the block:

} finally {
    IOUtils.closeQuietly(is);
    IOUtils.closeQuietly(os);
}

But Java 7 introduced a better solution: try-with-resources. C# 4 probably came first with something similar, Microsoft being quicker on the uptake than Snoracle.

try (
    is = new FileInputStream("foo.txt"),
    os = new FileOutputStream("D:/nonexistent/directory/bar.txt")
) {
    // work...
}


回答10:

finally always always runs. finally is like the catcher that never misses anything. In the example you mentioned, yes finally doesnt add any value. But finally is usually used to dispose/ release resources.