We’re all familiar with the try-catch idiom for handling exceptions. And of course, every primer on try-catch also introduces the finally block. It’s often unclear, however, when finally should be used. In other words, if I have a try-catch like so:
try { // do action } catch { // handle error } finally { // clean up }
Why can’t I just
try { // do action } catch { // handle error } // clean up
If this were an interview, we might answer mechanically: the finally will run even if the catch doesn’t catch the specific exception (if the catch is narrow), or if the catch rethrows the exception, or an exception occurs in the catch block. Putting the cleanup outside the finally will not be run in those cases.
But those cases are not too common, and then the finally is forgotten.
Consider the following case of a maintenance routine that requires a listening host be temporarily suspended. The maintenance routine may throw an exception, however, a higher-level exception handler (catch) already exists which implements the desired logging response:
StopHost(); DoMaintenance(); StartHost();
The problem, of course, is that when DoMaintenance throws an exception, it will bubble up to the catch handler and StartHost will never happen. This was an actual bug I encountered. The exception handler worked correctly, logging the fault, but the host was never restarted resulting in a system down until the next maintenance window.
I don’t really want to handle the exception at this level, but I do want to make sure that the host gets started again regardless of the outcome of the maintenance. Solution? finally!
StopHost(); try { DoMaintenance(); } finally { StartHost(); }
You don’t need a catch block to take advantage of finally.