Programmer’s Notebook: Uncaught Exception Handlers
Summary: learn how to use Thread.UncaughtExceptionHandler effectively in rich client (a.k.a. Swing) applications.
UPDATE: See One More Note on Uncaught Exception Handlers for important information about exceptions thrown from modal dialogs.
Quick Review
Java 5 introduced a new way to catch unexpected exceptions: Thread.UncaughtExceptionHandler. This is an interface with the following API:
public interface UncaughtExceptionHandler {
void uncaughtException(Thread t, Throwable e);
}
Your job is to write a class that implements this interface. You then register your implementation on a per-thread basis, or globally for every thread. To register your handler for a single thread you do something like this:
Thread.currentThread().setUncaughtExceptionHandler(new MyExceptionHandler());
To register your handler for every thread, do this:
Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler());
Notice that setDefaultUncaughtExceptionHandler(...) is a static method in the Thread class, while setUncaughtExceptionHandler(...) is a non-static method.
A Sample Swing App
Here is a very simple Swing application that shows two buttons:

If you click the “EDT Exception” button, it throws an exception on the event dispatch thread (EDT). If you click the “Thread Exception” button, it starts a background thread that throws an exception.
In both cases, a stack trace appears on the console. But the EDT exception messes up repainting, so the button does not paint properly until you move your mouse around a bit. Fortunately, Swing recovers and the app continues. Here is the complete source code:
public class Main extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Main().setVisible(true);
}
});
}
// throws an exception on the event dispatch thread
private Action edtAction = new AbstractAction("EDT Exception") {
public void actionPerformed(ActionEvent e) {
throw new RuntimeException("Exception generated on the EDT");
}
};
// throws an exception on another thread
private Action threadAction = new AbstractAction("Thread Exception") {
public void actionPerformed(ActionEvent e) {
new Thread("Sample Thread") {
public void run() {
throw new RuntimeException("Exception thrown on a thread");
}
}.start();
}
};
public Main() {
super("Uncaught Exception Handler Demo");
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
buttonPanel.add(new JButton(edtAction));
buttonPanel.add(new JButton(threadAction));
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Simple enough. Let’s add an uncaught exception handler.
MyExceptionHandler
Here is a simple uncaught exception handler that shows the exception message in a dialog box.
public class MyExceptionHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(final Thread t, final Throwable e) {
if (SwingUtilities.isEventDispatchThread()) {
showException(t, e);
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
showException(t, e);
}
});
}
}
private void showException(Thread t, Throwable e) {
String msg = String.format("Unexpected problem on thread %s: %s",
t.getName(), e.getMessage());
logException(t, e);
// note: in a real app, you should locate the currently focused frame
// or dialog and use it as the parent. In this example, I'm just passing
// a null owner, which means this dialog may get buried behind
// some other screen.
JOptionPane.showMessageDialog(null, msg);
}
private void logException(Thread t, Throwable e) {
// todo: start a thread that sends an email, or write to a log file, or
// send a JMS message...whatever
}
}
To use this handler, you must register it. Simply modify the code as follows:
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler());
...
Now, whenever an “unexpected” exception occurs, MyExceptionHandler kicks in and shows this lovely dialog box:

As an added bonus, the GUI repaints properly when this dialog displays.
This is Not Production Quality!
This is not a production-quality example! Let’s run down a list of features you will need to consider in a “real” application.
- Event Dispatch Thread (EDT) confinement. As our
UncaughtExceptionHandlershows, youruncaughtExceptionmethod must ensure it is on the EDT before showing an error dialog or interacting with other Swing GUI components. - Dialog ownership. If you use a dialog box, your app will need to use a proper owner
Window. My example simply passesnullas the owner, which is unacceptable in a real app. Failure to specify an owning window causes dialog boxes to get buried, which (as we found) causes many users to simply reboot their computers. Yes, the typical computer user does not know how to Alt-Tab through Windows, nor do they know how to use task manager to kill a process. Make sure you never bury a modal dialog! - Consider a non-modal dialog. Many modern apps show unexpected problems in a flashing indicator in the status bar.
- If you use a modal dialog, include an exit button. Sometimes when you hit OK, the exception occurs again, which triggers a new dialog. If modal, users are locked in and really need an exit button to abort the app.
- If you report errors back to “home base” via email or some other mechanism, do not do it on the event dispatch thread. Spawn a background thread.
- Make damn sure your unexpected exception hander includes try/catch blocks so you NEVER trigger yet another exception. If you do, you can get caught in infinite recursion as you display more and more errors.
- If your dialog is already visible, do not create another one. Consider the case when a table cell renderer throws an exception. Your dialog displays, which triggers a repaint event, which causes another exception, etc. If your dialog is already visible, ignore the next exception. Otherwise you’ll get caught in an infinite loop.
- If you are really sneaky, you can use
Robot.createScreenCapture()to capture a picture of your app. Be very, very careful about privacy concerns. This is only acceptable in an internal corporate environment…even then, there are significant ethical considerations.
- Consider the possibility of an unexpected exception before your main window appears. If your window is not even visible yet and you try to create a modal dialog using that window as its parent, your dialog won’t appear.
- If your customers are not comfortable with automated error reporting, consider adding a button that lets them choose to optionally send an email along with a screen shot.
- See also One More Note on Uncaught Exception Handlers for important information about exceptions thrown from modal dialogs.
As you can see, there are many details to consider. Real apps are just so darn messy…

