Since Java 5, we can set a default exception handler which will be called for all unhandled exceptions. This handler can be set by using following static method of java.lang.Thread:
public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
We have to provide an implementation of the interface Thread.UncaughtExceptionHandler , which has only one method:
@FunctionalInterface
public interface UncaughtExceptionHandler {
void uncaughtException(Thread t, Throwable e);
}
Examples
The following simple example shows how to use this feature:
public class Example1 {
public static void main(String[] args) throws Exception {
Thread.setDefaultUncaughtExceptionHandler(new MyHandler());
throw new Exception("A test exception");
}
private static final class MyHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.printf("exception caught:" + e);
}
}
} Outputexception caught:java.lang.Exception: A test exception
Customizing stacktrace
This feature can be used in a lot of ways. Following example shows how to use it to show only root cause of the exception.
In this example the source exception is wrapped multiple times. First, we are not going to use a customized UncaughtExceptionHandler to see the difference:
public class Example2 {
public static void main(String[] args) throws Exception {
method1();
}
static void method1() throws Exception {
try {
method2();
} catch (Exception e) {
throw new Exception("rethrowing from method1()", e);
}
}
private static void method2() throws Exception {
try {
method3();
} catch (Exception e) {
throw new Exception("rethrowing from method2()", e);
}
}
private static void method3() throws Exception {
try {
test4();
} catch (Exception e) {
throw new Exception("rethrowing from method3()", e);
}
}
private static void test4() throws Exception {
throw new Exception("root exception from method4()");
}
} OutputException in thread "main" java.lang.Exception: rethrowing from method1() at com.logicbig.example.Example2.method1(Example2.java:13) at com.logicbig.example.Example2.main(Example2.java:6) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) Caused by: java.lang.Exception: rethrowing from method2() at com.logicbig.example.Example2.method2(Example2.java:21) at com.logicbig.example.Example2.method1(Example2.java:11) ... 6 more Caused by: java.lang.Exception: rethrowing from method3() at com.logicbig.example.Example2.method3(Example2.java:29) at com.logicbig.example.Example2.method2(Example2.java:19) ... 7 more Caused by: java.lang.Exception: root exception from method4() at com.logicbig.example.Example2.test4(Example2.java:34) at com.logicbig.example.Example2.method3(Example2.java:27) ... 8 more
Now let's use a UncaughtExceptionHandler to show only root cause stacktrace:
public class Example3 {
public static void main(String[] args) throws Exception {
Thread.setDefaultUncaughtExceptionHandler(new MyHandler());
Example2.method1();
}
private static final class MyHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
Throwable rootCause = ExceptionUtils.getRootCause(e);
rootCause.printStackTrace(System.err);
}
}
} Outputjava.lang.Exception: root exception from method4() at com.logicbig.example.Example2.test4(Example2.java:34) at com.logicbig.example.Example2.method3(Example2.java:27) at com.logicbig.example.Example2.method2(Example2.java:19) at com.logicbig.example.Example2.method1(Example2.java:11) at com.logicbig.example.Example3.main(Example3.java:9) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Note that, in above example we used ExceptionUtils of apache-commons (dependency included in project browser below).
When it doesn't work?
- If another handler is set (by using static method
Thread.setUncaughtExceptionHandler ) in other part of the application after us.
- If exception is handled.
- In a servlet container (like tomcat) where exception is handled and redirected to a servlet etc to show a web-based error message. There we need to use error mapping per servlet specification instead.
Example ProjectDependencies and Technologies Used: - commons-lang3 3.5:
Apache Commons Lang, a package of Java utility classes for the
classes that are in java.lang's hierarchy, or are considered to be so
standard as to justify existence in java.lang.
- JDK 1.8
- Maven 3.3.9
|