在我的 JavaFX 应用程序中,我想创建一个全局未捕获异常处理程序,它创建一个显示错误消息和异常堆栈跟踪的对话窗口,然后终止。我正在使用 Thread.setDefaultUncaughtExceptionHandler()
并在其中创建对话框,但异常处理程序中的代码本身会在调用时不断抛出异常。
原因是当JavaFX 应用程序线程中抛出任何未捕获的异常时,JVM 会终止该线程。并且 JavaFX 线程必须正在运行以创建 JavaFX 组件 - 因此无法在异常处理程序中创建类似的对话框......所以我的问题是最好的方法是什么?我想在发生未捕获的异常时向用户显示一条消息,而不是让应用程序突然终止。
这是我一直在使用的:
public void start(Stage primaryStage) throws IOException {
Thread.setDefaultUncaughtExceptionHandler((Thread t, Throwable e) -> {
Dialogs.create().title("Error")
.message("An uncaught exception was thrown in thread \"" + t
+ "\". Click below to view the stacktrace, or close this "
+ "dialog to terminate the application.")
.style(DialogStyle.NATIVE)
.showExceptionInNewWindow(e);
Platform.exit();
});
primaryStage.show();
method();
}
public void method() throws IOException {
//Performs file i/o operations and throws IOException if an error occurs
throw new IOException();
}
程序后面也可能抛出更多的异常。 (顺便说一句,我正在使用 ControlsFX 库创建对话框窗口。)这是我在运行代码时收到的错误消息:
Exception in Application start method
Exception: java.lang.IllegalStateException thrown from the UncaughtExceptionHandler in thread "main"
最佳答案
我认为这里发生的是start()
方法中抛出的异常被调用该方法的代码捕获。因此,start()
方法中抛出的任何内容都不会由您的异常处理程序处理(这不是未捕获 异常)。
但是,在 start()
方法完成后抛出的异常将由您的异常处理程序处理。
但是请注意,异常将在抛出它们的线程中处理。因此,只要在 FX 应用程序线程上抛出这些异常,您的代码就会工作,但不适用于在后台线程中抛出的异常(因为您无法在后台线程中创建和显示对话框)。
为了涵盖所有可能发生的情况:
- 如果可能在
start()
方法中抛出异常或错误,请将该代码放在try
-catch
中按常规方式拦截和处理。 - 设置默认 未捕获异常处理程序以调用代码以使用
Platform.runLater()
显示对话框。这将处理在 FX 应用程序线程外抛出的异常。 - 在 FX 应用程序线程上设置未捕获的异常处理程序以调用代码以直接显示对话框。
示例(在 start()
方法中以 50% 的概率抛出错误):
import java.io.IOException;
import java.util.Random;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import org.controlsfx.dialog.Dialogs;
import org.controlsfx.dialog.DialogStyle;
public class UncaughtExceptionHandlerExample extends Application {
@Override
public void start(Stage primaryStage) {
Thread.setDefaultUncaughtExceptionHandler((t, e) -> Platform.runLater(() -> showErrorDialog(t, e)));
Thread.currentThread().setUncaughtExceptionHandler(this::showErrorDialog);
try {
Button button = new Button("Create error");
button.setOnAction(event -> {
throw new Error("Boom!");
});
Button backgroundErrorButton = new Button("Create error in background thread");
backgroundErrorButton.setOnAction(event -> {
new Thread(() -> {
throw new Error("Boom");
}).start();
});
HBox root = new HBox(5, button, backgroundErrorButton);
Scene scene = new Scene(root, 400, 80);
primaryStage.setScene(scene);
primaryStage.show();
if (new Random().nextDouble() < 0.5) {
throw new Error("Boom");
}
} catch (Throwable t) {
showErrorDialog(Thread.currentThread(), t);
}
}
private void showErrorDialog(Thread t, Throwable e) {
Dialogs.create().title("Error")
.message("An uncaught exception was thrown in thread " + t
+ ". Click below to view the stacktrace, or close this "
+ "dialog to terminate the application.")
.style(DialogStyle.NATIVE)
.showExceptionInNewWindow(e);
Platform.exit();
}
public static void main(String[] args) {
launch(args);
}
}
顺便说一句,我不认为 JVM 会在 FX 应用程序线程发生未捕获的异常时终止它。
关于java - 如何创建使用 JavaFX 的默认异常处理程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25145956/