I Finally Understand The Finally Part Of A Try/Catch Control Statement

I love a good Try / Catch block! In fact, I used one just the other day when dealing with transactional rollbacks involving 3rd party APIs. But, as far as the Try / Catch control flow goes, I never quite understood the need for a "Finally" statement; if you have a Catch statement, why not just move the contents of the "Finally" statement to after the body of the Try / Catch block? People have tried to explain this to me many times, and I'm sure I've nodded and said, "Oh, that makes sense." But, it never really did made sense - until, that is, I read Eloquent Javascript by Marijn Haverbeke.

My moment of clarity came when Haverbeke demonstrated a Try / Catch block that didn't have a Catch statement; it only had Try and Finally. Honestly, I didn't even know such a thing was technically possible! But seeing this suddenly made so much sense - if you don't have a Catch statement, then of course you can't just move the contents of the Finally statement to after the Try / Catch block! A Finally statement would be the only way to execute localized clean-up.

To explore the Try / Catch / Finally trinity a bit more, I set up a few demos. The first uses all three statements - this is the kind of scenario in which the Finally statement never made any sense to me.

<!DOCTYPE html> <html> <head> <title>Understanding Try/Catch And Finally</title> <script type="text/javascript"> // Execute a try/catch block with a finally. try { // Throw an error so the catch is triggered. throw( new Error( "Blam!!!!" ) ); } catch( error ){ // Catch the error. console.log( "Caught your error:", error.message ); } finally { // Execute the clean-up code. console.log( "Finally!" ); } // We got past our try/catch. console.log( "Back to safety." ); </script> </head> <body> <!-- Left intentionally blank. --> </body> </html>

Here, the Try statement throws an error, Catch handles it, and the Finally executes clean-up. When we run the above code, we get the following console output:

Caught your error: Blam!!!!

Finally!

Back to safety.

As you can see, the Catch statement handled the error and the Finally statement executed afterward. While it is not demonstrated by this specific control flow, the Finally statement would have executed regardless of whether or not an exception was thrown.

At this point, I would look at the code and wonder what role the Finally statement was actually playing? As far as I have ever been concerned in the past, the Finally code could simply be factored-out with the exact same end-result.

The Finally statement starts to make more sense, however, when you remove the Catch statement from the workflow:

<!DOCTYPE html> <html> <head> <title>Understanding Try/Catch And Finally</title> <script type="text/javascript"> // Execute a TRY-ONLY block with a finally. try { // Throw an error so the catch is triggered. throw( new Error( "Blam!!!!" ) ); } finally { // Execute the clean-up code. console.log( "Finally!" ); } // We got past our try/catch. console.log( "Back to safety." ); </script> </head> <body> <!-- Left intentionally blank. --> </body> </html>

Here, the Try statement raises an unhandled exception; the Finally statement then becomes the only way to execute any kind of local clean-up before the exception bubbles up through the call stack. When we run this code, we get the following console output:

Finally!

[Break On This Error] throw( new Error( "Blam!!!!" ) );

As you can see, the Finally statement executed before the error was handled by the environmental container.

I am not sure why I would have a Try statement without a Catch statement; but, that seems to be the only structure in which my brain will let me justify the Finally statement.

So far, we've been looking at a single call context; when we add an additional function call to the stack, however, it gets even more interesting / confusing. In this last demo, we'll use both a Catch and a Finally statement; and, just to make this extra special, both of these statements will contain their own Return statement:

<!DOCTYPE html> <html> <head> <title>Understanding Try/Catch And Finally</title> <script type="text/javascript"> // I contain a try/catch/finally block to see how return // statements interact with the function error handling. function test(){ try { // Throw an error so the catch is triggered. throw( new Error( "Blam!!!!" ) ); } catch( error ){ // Log our location. console.log( "... catch" ); // Return out of our try/catch. return( "In Catch" ); } finally { // Log our location. console.log( "... finally" ); // Return out of our finally. return( "In Finally" ); } } // Log the results of our test() method. console.log( test() ); </script> </head> <body> <!-- Left intentionally blank. --> </body> </html>

Unless you know 100% what the Finally statement does, this has to be confusing code! When we run it, we get the following console output:

... catch

... finally

In Finally

So, the Catch statement runs, executes its Return statement, which hands control over to the Finally statement, which runs and then executes its Return statement (which is the value that gets passed back to the call stack). But, what if the Finally statement didn't have its own Return statement? Well, in that case (not shown in the code), the Finally statement would run and then the return value of the Catch statement would get passed back to the call stack - isn't that obvious?!? (he says jokingly knowing that it's hard to write code more confusing than this).

After reading Eloquent Javascript by Marijn Haverbeke, my understanding of the Finally statement within a Try / Catch block is much more clear. But, to be honest, I am still having a little trouble seeing a great use-case for it. I suppose that to some extent, it can be used in place of a nested Try / Catch block; or, a Catch statement that uses a throw or rethrow approach.

Tweet This Provocative thoughts by @BenNadel - I Finally Understand The Finally Part Of A Try/Catch Control Statement Woot woot — you rock the party that rocks the body!







