I don't know if this is the best that Java currently has to offer, but this is what I did a while back.
First all interesting activity likely to crash was dispatched via a command pattern. This application consisted of hitting an application server over the internet, so a lot could go wrong. The exceptions were caught by the command dispatcher and the appropriate result displayed to the user (generally showing an error dialog followed by a shutdown and an e-mail sent about the crash).
Second, a custom event queue was used in Swing to catch any exceptions that happen on the event thread. I would hope that Java has a better solution by now, but basically when an exception happened you had to check if your code was involved, otherwise some Swing bugs could crash your application, which isn't pleasant. And of course recursion had to be checked for (the crash repeating itself over and over again as you try to display a message to the user).
By the way, most any crash will keep your JVM going, including out of memory errors, enough to send an e-mail in most cases, as after an out of memory error generally the error releases enough of the stack (and therefore heap) to allow for further garbage collection and letting your code live. But in such an event you should still exit quickly. IDEA keeps going after an out of memory error, but often isn't functioning well. They would be better off exiting, IMO.
You push a new Queue with the following and subclass EventQueue to link in your behavior.
Toolkit.getDefaultToolkit().getSystemEventQueue().push(newQueue);