What is the point of finally in a try catch/except finally statement
Exception HandlingFinallyException Handling Problem Overview
I have used try-catch/except-finally variants in many languages for years, today someone asked me what is the point of finally and I couldn't answer.
Basically why would you put a statement in finally instead of just putting it after the whole try-catch block? Or in other words is there a difference between the following blocks of code:
try{ //a}
catch {//b}
finally {//c}
try{//a}
catch{//b}
//c
EDIT:
PEOPLE, I know what finally does, I have been using it for ages, but my question is in the above example putting //c
in finally seems redundant, doesn't it?
Exception Handling Solutions
Solution 1 - Exception Handling
The purpose of a finally
block is to ensure that code gets run in three circumstances which would not very cleanly be handled using "catch" blocks alone:
- If code within the
try
block exits viareturn
- If code within a
catch
block either rethrows the caught exception, or--accidentally or intentionally--ends up throwing a new one. - If the code within the
try
block encounters an exception which for which thetry
has nocatch
.
One could copy the finally
code before every return
or throw, and wrap catch
blocks within their own try/catch to allow for the possibility of an accidental exception occurring, but it's far easier to forgo all that and simply use a finally
block.
BTW, one thing I wish language designers would include would be an exception
argument to the finally
block, to deal with the case where one needs to clean up after an exception but still wants it to percolate up the call stack (e.g. one could wrap the code for a constructor in such a construct, and Dispose
the object under construction if the constructor was going to exit with an exception).
Solution 2 - Exception Handling
Finally block is executed even if an exception thrown in the try block. Therefore, for instance if you opened a stream before, you may want to close that stream either an exception is thrown or not. Finally block is useful for such an issue.
Solution 3 - Exception Handling
finally
is a syntactic sugar to allow DRY principle in try-catch
pattern. Exception is usually thrown if the library code has not enough information to handle some state and wants the client code to solve it. If you don't have library-client code separation, you can handle everything by if
instead of try
.
Let's see a standard situation without finally
:
void myFunction() {
var r = allocateResources();
r.doSomething();
if(somethingBadHappens) {
freeResources(r);
throw new Exception(CODE42);
}
r.doSomethingMore();
freeResources(r);
}
In the snippet above, you repeat freeResources()
: this can be multiple statements which you need to repeat. This smells and finally
block is the solution for clean code:
void myFunction() {
var r = allocateResources();
try {
r.doSomething();
if(somethingBadHappens) throw new Exception(CODE42);
r.doSomethingMore();
}
finally {
freeResources(r);
}
happyFunction();
}
Let's realize three levels of abstraction:
- A1 is the library code providing
allocateResources()
function - A2 is our code providing
myFunction
, consuming A1 - A3 is some client code consuming
myFunction
in try-catch block:
function A3code() {
try {
myFunction();
doSomething();
}
catch(Exception e) {
// no hanging resources here
Console.WriteLine(e);
}
}
Now let's see what can happen:
- if
allocateResources()
throws in A1, we don't know how to handle it in A2 (A2 code can be run in Console-free environment), so we delagate the situation to A3 without adding any further code. If Exception is thrown here, the finally block is not executed, sincefinally
is bound totry
which was not entered. - if
somethingBadHappens
in try block, the stack unwinds to A3 where the situation is handled BUT before itfinally
block is executed, so we don't need to repeat it if no exceptions happen. - before
finally
we can addcatch
block and try to resolve some potential exceptions from A1 which may appear in callingr.doSomething
methods. Usually we want to handle exceptions as soon as possible to make the client code (A3) more comfortable for client coders. happyFunction()
is executed only if nothing throws inmyFunction()
(inside or outside oftry
block).
As @supercat points out, the finally
block is executed also if try
block exits via return. I suggest you avoid this bad habit and have only one return in every function (maybe some early exists at the very beginning of functions). The reasons for single-return functions are:
- The code is more readable: you look at the end and see WHAT the function returns. In multiple returns you must find all return occurences, inspect all the ifs, think about when the ifs are satisfied and only then you know what the function returns.
- The code can be optimized by compilers, see copy elision.
The reason for multiple returns is avoiding many nested ifs, but there are other techniques to solve it. Exception
s are exception in this rule.
Solution 4 - Exception Handling
Learn by example
let v = 0;
function f() {
try {
v = 1;
return 2;
} finally {
v = 3;
return 4;
}
v = 5;
return 6;
}
const r = f();
console.log(r, v);
following prints "3, 4"
Solution 5 - Exception Handling
Finally
make sure your code is executed even if you get an exception.
The finally block is useful for cleaning up any resources allocated in the try block as well as running any code that must execute even if there is an exception
http://msdn.microsoft.com/en-us/library/zwc8s4fz(v=vs.80).aspx