Thread.setDefaultUncaughtExceptionHandler能捕获新创建的非主线程中未被try-catch处理的RuntimeException和Error(如NullPointerException、OutOfMemoryError),但不捕获checked exception;必须在子线程启动前于main方法开头设置,且主线程异常需单独用Thread.currentThread().setUncaughtExceptionHandler处理。

Thread.setDefaultUncaughtExceptionHandler 是 Java 中用于捕获线程中未被捕获异常的全局兜底机制,但它只对“非主线程”生效,且不能捕获主线程(main thread)的未处理异常——主线程需用 Thread.currentThread().setUncaughtExceptionHandler(...) 单独设置。
它能捕获哪些异常?
该方法设置的是 JVM 级别的默认处理器,适用于:
• 所有新创建的、未显式设置自己异常处理器的非主线程
• 这些线程在 run() 方法中抛出、且未被 try-catch 捕获的 RuntimeException 或 Error(比如 NullPointerException、ArrayIndexOutOfBoundsException、OutOfMemoryError 等)
• 注意:它不捕获已声明检查型异常(checked exception),因为这类异常编译期就必须处理,不可能“未处理”
怎么正确设置?
必须在任何子线程启动前调用,通常放在 main 方法开头:
// 推荐写法:设置全局默认处理器
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
System.err.println("线程 [" + t.getName() + "] 发生未捕获异常:");
e.printStackTrace();
});
new Thread(() -> {
throw new RuntimeException("模拟崩溃");
}).start();
}
常见误区和注意事项
• 主线程异常不会走这个处理器 —— main 方法里抛出的异常需要单独捕获或靠 JVM 默认行为(打印堆栈并退出)
• 已设置过 setUncaughtExceptionHandler 的线程,会优先使用自己的处理器,不走全局默认
• Lambda 表达式或匿名类实现时,确保 handler 逻辑简洁可靠(避免再抛异常或阻塞)
• 在 Web 容器(如 Tomcat)或框架(如 Spring)中,可能已有上层异常拦截机制,该设置仍有效但可能被覆盖或忽略
配合主线程兜底更完整
若想统一处理所有线程(含主线程),建议组合使用:
• Thread.setDefaultUncaughtExceptionHandler(...) 覆盖子线程
• Thread.currentThread().setUncaughtExceptionHandler(...) 单独为主线程设一次
• 对于 ExecutorService,推荐用 ThreadFactory 统一注入 handler,比依赖默认更可控


















