Java 中如何记录未捕获的异常?
Java 记录未捕获异常:实现 Thread.UncaughtExceptionHandler 接口并设为默认处理器,所有未被 try-catch 捕获的异常都会触发记录。本文给出完整实现。
核心:实现 Thread.UncaughtExceptionHandler 接口,在 uncaughtException() 方法中用日志框架记录异常,然后通过 Thread.setDefaultUncaughtExceptionHandler() 注册为全局默认处理器。
完整实现
import java.util.logging.Level;
import java.util.logging.Logger;
public class GlobalExceptionHandler implements Thread.UncaughtExceptionHandler {
private static final Logger LOGGER = Logger.getLogger(GlobalExceptionHandler.class.getName());
@Override
public void uncaughtException(Thread t, Throwable e) {
LOGGER.log(Level.SEVERE, "线程 " + t.getName() + " 中出现未捕获异常", e);
}
}
在程序入口注册:
public class Main {
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler(new GlobalExceptionHandler());
// 正常业务逻辑...
}
}
此后任何线程中未被 catch 的异常都会触发 uncaughtException() 方法。
对单个线程设置
Thread thread = new Thread(() -> {
throw new RuntimeException("出错了");
});
thread.setUncaughtExceptionHandler((t, e) -> {
System.err.println("线程 " + t.getName() + " 异常: " + e.getMessage());
});
thread.start();
线程池中的注意事项
ThreadPoolExecutor 的 execute() 提交的 Runnable 抛出的异常会走 UncaughtExceptionHandler;但 submit() 返回的 Future 中的异常不会——它被封装在 Future 里,调用 get() 时才抛出。
观测云对照
生产环境推荐用观测云 APM 的 Java 探针,自动捕获未处理异常并关联到具体的请求 Trace,包含完整的堆栈和上下文信息,在观测云控制台中聚合展示和告警。
常见问题(FAQ)
Q:Spring Boot 项目需要手动注册吗?
A:Spring Boot 的 @ControllerAdvice + @ExceptionHandler 处理 Controller 层的异常;非 Web 层的异常仍建议注册全局 UncaughtExceptionHandler。
Q:捕获后进程会退出吗?
A:取决于 JVM 配置。默认情况下主线程的未捕获异常会导致进程退出,非守护线程的异常只导致该线程终止。
Q:log4j2/SLF4J 怎么用?
A:把上面示例中的 java.util.logging 替换为你项目使用的日志框架即可,逻辑不变。