Most errors shouldn't be handled; that's the reason most exception handlers simply log the error.
I've said it here before, but this is my classification of errors that exceptions are commonly used for:
1) Programming error: null pointer exception, library invariants broken, etc. These generally shouldn't be caught, and could arguably be replaced by fatal assertions, but that's typically not a polite thing to do in a library.
2) Non-deterministic failure condition: something outside the control of the calling code failed in a way that it cannot predict ahead of time. A network connection broke, a file was deleted unexpectedly, a device was detached, database server died, etc. There's something of an argument for annotating functions that can fail this way in the manner of Java's checked exceptions and it has a strong relationship with the IO monad in Haskell (and similar problems with encapsulation and hiding implementation details). These kinds of errors can sometimes be handled, and handling them with exceptions isn't much better or worse than error codes. An advantage of exceptions is that they makes it easy to abort the whole task and go back to the request handler (server code) or event dispatch loop (UI code). Exceptions can carry more state than error codes, too.
3) Business logic problem: the user, for want of a better term, of the program tried to do something that is not allowed / possible, and the program needs to abort the current task and inform the user of the problem. Exceptions are as good a means of aborting as most others. These should only be caught at the top level, whereupon they can be converted into something for human / 422 response / whatever consumption.
In almost all cases, you cannot proceed and there is nothing you can do in reaction to the error. Aborting and unwinding the call stack is usually the correct thing to do.