Another situation where finally is useful is to ensure that "manual" locks get released (locks implemented with the language's synchronizing structures internally use finally for this purpose). When doing this, however, there is a detail which is sometimes overlooked: locks are often acquired for the purpose of allowing code to momentarily violate an object's invariants and re-establish them before anyone else can notice. If an exception occurs which would leave an object's invariants in an improper state, the proper behavior is generally not to leave the lock held, but rather ensure that a variable is set to indicate that has occurred, and have anyone that acquires the lock check this variable and throw an exception if it is set.
If one encapsulates the lock-is-valid variable within the lock object, the code might look like:
void insertItem(...)
{
try
{
myLock.acquire();
myLock.enterDanger();
...
myLock.leaveDanger();
}
finally
{
myLock.release();
}
}
Code which never modifies the guarded object but simply reads it would never have to "enterDanger". If release gets called while the lock is still indanger state, it may wish to capture the current stack trace; pending or future calls to myLock.acquire should throw an exception, possibly including that stack trace as supplemental information.
Note that one could try instead to invalidate myLock within a catch block, but one must then ensure that nobody adds a catch block to the try block to handle expected exceptions without invalidating the lock. If an expected exception occurs in an unexpected place, the guarded object might be left in a corrupt state without triggering the catch that was supposed to invalidate it (the execution of the more specific catch would prevent execution of the less-specific one).