Search code examples
javaexceptionjvmuncaught-exceptionuncaughtexceptionhandler

Do errors thrown within UncaughtExceptionHandler get swallowed?


Thread.UncaughtExceptionHandler states that when the method which handles uncaught exceptions itself throws an exception, that exception will be ignored:

void uncaughtException(Thread t, Throwable e):

Method invoked when the given thread terminates due to the given uncaught exception.

Any exception thrown by this method will be ignored by the Java Virtual Machine.

However when I tested it, the JVM did not ignore the exceptions handled by the uncaught exception handler`:

public static void main(final String args[]) {
    Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(Thread arg0, Throwable arg1) {
            throw new java.lang.RuntimeException("e2");
        }
    });
    throw new RuntimeException("e1");
}

Eclipse Console output (JRE 1.7):

Exception: java.lang.RuntimeException thrown from the UncaughtExceptionHandler in thread "main"

Another oddity I found out is that the output I get isn't coming from System.err. It seems to be from another stream altogether. I verified this by redirecting System.err to System.out, but I'm still getting "red" output:

public static void main(final String[] args) {
    System.setErr(System.out);
    System.out.println(System.err == System.out);
    System.err.println("this is black color");
    try {
        throw new Error("test stacktrace color");
    } catch (Throwable e) {
        e.printStackTrace();
    }
    try {
        Thread.sleep(2500);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            throw new RuntimeException("from handler");
        }
    });
    throw new RuntimeException("from main");
}

The output (bolded signifies red color):

true

this is black color

java.lang.Error: test stacktrace color at asf.df.main(df.java:13)

Exception: java.lang.RuntimeException thrown from the UncaughtExceptionHandler in thread "main"

What's the explanation for these phenomenons?

What happens to errors thrown within UncaughtExceptionHandler? What's the expected (documented or guaranteed) behavior?


Solution

  • HotSpot JVM prints the exceptions thrown from the UncaughtExceptionHandler. See JavaThread::exit

        if (HAS_PENDING_EXCEPTION) {
          ResourceMark rm(this);
          jio_fprintf(defaultStream::error_stream(),
                "\nException: %s thrown from the UncaughtExceptionHandler"
                " in thread \"%s\"\n",
                pending_exception()->klass()->external_name(),
                get_thread_name());
          CLEAR_PENDING_EXCEPTION;
        }
    

    JVM prints these exceptions itself directly on stderr regardless of the System.err state - whether it was redirected or not.

    Well, this kind of warning does not affect the application - in this sense the exception is "ignored". But you are right, this behavior is not obvious. Javadoc is misleading and is better to be fixed.