是否吞噬了UncaughtExceptionHandler中抛出的错误?

Thread.UncaughtExceptionHandler声明当处理未捕获的exception的方法本身抛出exception时,该exception将被忽略:

void uncaughtException (Thread t,Throwable e):

当给定线程由于给定的未捕获exception而终止时调用的方法。

Java虚拟机将忽略此方法抛出的任何exception。

但是当我测试它时,JVM没有忽略未捕获的exception处理程序处理的exception:

 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控制台输出(JRE 1.7):

exception:从线程“main”中的UncaughtExceptionHandler抛出java.lang.RuntimeException

我发现的另一个奇怪的是我得到的输出不是来自System.err 。 它似乎完全来自另一个流。 我通过将System.err重定向到System.out来validation这一点,但我仍然得到“红色”输出:

 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"); } 

输出(粗体表示红色):

真正

这是黑色

java.lang.Error:在asf.df.main上测试stacktrace颜色(df.java:13)

exception:从线程“main”中的UncaughtExceptionHandler抛出java.lang.RuntimeException

这些现象的解释是什么?

UncaughtExceptionHandler中抛出的错误会发生什么? 什么是预期(记录或保证)行为?

HotSpot JVM打印从UncaughtExceptionHandler抛出的exception。 请参阅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; } 

无论System.err状态如何 – 无论是否重定向,JVM都会直接在stderr上打印这些exception。

好吧,这种警告不会影响应用程序 – 在这个意义上,exception被“忽略”。 但你是对的,这种行为并不明显。 Javadoc具有误导性,最好修复。

忽略exception,并且从非主线程抛出时继续处理。

如果它在main中抛出,则返回的错误代码为非零。

未处理的exception通过syserr记录。

 public static void main(final String[] args) { final Thread myThread = new Thread(new Runnable() { @Override public void run() { Thread.currentThread() .setUncaughtExceptionHandler(new UncaughtExceptionHandler() { @Override public void uncaughtException(final Thread t, final Throwable e) { System.out.println("In child UncaughtExceptionHandler at " + java.time.Instant.now()); throw new RuntimeException("From child thread UncaughtExceptionHandler" + java.time.Instant.now()); } }); throw new RuntimeException("from runnable"); } }); Thread.currentThread() .setUncaughtExceptionHandler(new UncaughtExceptionHandler() { @Override public void uncaughtException(final Thread t, final Throwable e) { System.out.println("In main UncaughtExceptionHandler " + java.time.Instant.now()); throw new RuntimeException("From main thread UncaughtExceptionHandler" + java.time.Instant.now()); } }); myThread.start(); LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2)); System.out.println("After child thread: " + java.time.Instant.now()); //Will result in a non-zero return code throw new RuntimeException("from main"); } 

输出:

在孩子UncaughtExceptionHandler中,2014-07-19T04:10:46.184Z

exception:从线程“Thread-0”中的UncaughtExceptionHandler抛出java.lang.RuntimeException后子线程:2014-07-19T04:10:48.197Z主UncaughtExceptionHandler 2014-07-19T04:10:48.197Z

exception:从线程“main”中的UncaughtExceptionHandler抛出java.lang.RuntimeException