Finally blocks permit you, as a developer, to tidy up after yourself, regardless of the actions of preceeding code in the try{} block encountered errors, and have others have pointed out this, is falls mainly under the umbrella of freeing resources - closing pointers / sockets / result sets, returning connections to a pool etc.
@mats is very correct that there is always the potential for "hard" failures - finally blocks shouldn't include mission critical code, which should always be done transactionally inside the try{}
@mats again - The real beauty is that it allows you throw exceptions back out of your own methods, and still guarantee that you tidy up:
try
{
StreamReader stream = new StreamReader("foo.bar");
mySendSomethingToStream(stream);
}
catch(noSomethingToSendException e) {
//Swallow this
logger.error(e.getMessage());
}
catch(anotherTypeOfException e) {
//More serious, throw this one back
throw(e);
}
finally
{
stream.close();
}
So, we can catch many types of exception, process them differently (the first allows execution for anything beyond the try{}, the second effectively returns), but always neatly and tidily clear up.