Advanced exception handling in Java -Thread.UncaughtExceptionHandler

Yosi Mizrachi
4 min readMay 12, 2017

--

Today I want to talk about Java’s Thread.UncaughtExceptionHandler and how it can help us catch those unexpected scenarios where our code would come to a halt.

All of us developers out there are dealing, daily, with code execution that went wrong. Be it exceptions, errors or anything that breaks our normal code flow, it happens. That is fine — all part of a day’s job! If you think your code is flawless, wake up! There is no such thing.

Lets start with a simple example. Here’s a naive method that takes user input, divide them, print and return the result to the caller:

private int divideAndCrash(int argA, int argB) {
int result = argA / argB;
System.out.println(result);
return result;
}

Simple enough.
Now since we aren’t checking the input arguments for valid values, what will happen when the user enters zero as the value for argument argB? all hell break loose :)

Exception in thread “main” java.lang.ArithmeticException: / by zero

Now, we all know some of the “tools” we have to mitigate and defend our code like the infamous try-catch which will — should the code break, catch the exceptions for us and let us decide what to do with them:

private static int divideAndDontCrash(int argA, int argB) {
int result = 0;
try {
result = argA / argB;
System.out.println(result);
} catch (ArithmeticException e) {
System.out.println("Failed to divide by zero.");
}
return result;
}

But we can’t be wrapping every single line of code with a try-catch, that would be just plain awful in so many levels. So how do we handle those times where some part of our code threw an exception and we didn’t catch it?

Come to the rescue -Thread.UncaughtExceptionHandler

Lets consider this scenario — you lunched an app into production with a lot of active users which run your app daily and bugs are starting to show up.

Of course you have a nice, detailed log file about every important detail in the app which gets uploaded on a regular basis and you start to analyze the logs just to realize that in the scenario of a crash all code execution, including your log prints are stopped and the crash stack, which is what you need so bad in order to solve this issue is not in the logs.

Setting an UncaughtExceptionHandler on your threads is your app’s last stop before it crash, which lets you deal with exactly that — save that last pieces of information, close resources, shutdown gracefully which eventually will help you solve your bug.

The UncaughtExceptionHandler is an interface inside the Thread class (I’ll just call it handler for brevity). Lets read what the docs has to say about it:

/**
* Interface for handlers invoked when a <tt>Thread</tt> abruptly
* terminates due to an uncaught exception.
* <p>When a thread is about to terminate due to an uncaught exception
* the Java Virtual Machine will query the thread for its
* <tt>UncaughtExceptionHandler</tt> using
* {
@link #getUncaughtExceptionHandler} and will invoke the handler's
* <tt>uncaughtException</tt> method, passing the thread and the
* exception as arguments.
* If a thread has not had its <tt>UncaughtExceptionHandler</tt>
* explicitly set, then its <tt>ThreadGroup</tt> object acts as its
* <tt>UncaughtExceptionHandler</tt>. If the <tt>ThreadGroup</tt> object
* has no
* special requirements for dealing with the exception, it can forward
* the invocation to the {
@linkplain #getDefaultUncaughtExceptionHandler
* default uncaught exception handler}.
*
*
@see #setDefaultUncaughtExceptionHandler
*
@see #setUncaughtExceptionHandler
*
@see ThreadGroup#uncaughtException
*
@since 1.5
*/

So basically when a thread such as the main thread is about to terminate due to an uncaught exception the virtual machine will invoke the thread’s UncaughtExceptionHandler for a chance to perform some error handling like logging the exception to a file or uploading the log to the server before it gets killed.

It is important to understand how it works.

Every Thread is a member of a ThreadGroup and if the terminated thread doesn’t have an explicitly set handler than it will forward to the thread group handler. If the thread group doesn’t hold any special handler for such cases, it will eventually call it’s default uncaught exception handler.

Setting this handler is a per-thread base solution. Thread A will not use Thread’s B handler and vice versa. It is not a symmetric relation. Unless your threads are all a part of the same thread group and you have explicitly set an UncaughtExceptionHandler on the thread group, your threads can have different handlers performing different things in such scenarios where the thread terminates.

Setting up a handler is as simple as it gets — just create your own by implementing the interface:

public class LastChanceHandler implements Thread.UncaughtExceptionHandler {

@Override
public void uncaughtException(Thread t, Throwable e) {
// do something here - log to file and upload to server/close resources/delete files...
}
}

and set your handler to the thread, usually the main thread on GUI applications since uncaught exceptions will make the entire app crash:

Thread.setDefaultUncaughtExceptionHandler(new LastChanceHandler());

Last thing that I should add — George, one of the readers mentioned I should delegate the exception back to the original UncaughtExceptionHandler, this is to give back the control of exceptions to the systems. Otherwise we will “swallow” those exceptions and we might continue running in a some broken app state which is a bad thing. Crashing is probably a better choice than running in a wrong state. Thanks for pointing this out George!

And… thats it, were done!

So we’ve learned what is an UncaughtExceptionHandler and how it can serve us dealing with crashes and bugs in production when otherwise - the part that we really need in our log file wouldn’t appear- the crash stack trace. Yes there are different services out there like Crashlytics that will help on that area and are very powerful tools but hey, how do you think they work behind the scenes? hint — UncaughtExceptionHandler.

Hope it will help someone out there. This is my first blog post and I’d love to hear what you think.

--

--