Exceptions are the best thing since sliced bread. If you use them properly, you can write code of much higher quality than without them. I think of the old days before exceptions, and I wonder how we managed to get anything done back then. There is, however, one little very important thing missing from implementations of exceptions in all languages that I know of, and it has to do with transactions.
At a high level, exception handling
looks structurally similar to transactional processing. In both cases we have a
block of guarded code, during the execution of which we acknowledge the
possibility that things may go wrong, in which case we are
given the opportunity to leave things exactly
as we found them. So, given this similarity,
it is no wonder that one can nicely facilitate the other, as this sample code shows: