java - 静态初始化程序中的异常处理

标签 java javafx

通常,我通过显示一些带有详细信息的自定义警报 (JavaFX) 来处理异常,但当我的类的静态初始化程序运行时,JavaFX 运行时根本不会初始化。

有没有办法处理这种异常,而不需要像动物一样打印其内容来输出?

public class MyStaticInitializedClass {

    static {
        try {
            //do the things that may throw exception
        } catch(Exception ex) {
            ExceptionHandler.showException(ex);
        }
    }

}

public class ExceptionHandler {

    public static void showException(Exception ex) {
        //constructs JavaFX alert with exception details
        alert.show();
    }

}

最佳答案

首先考虑是否不应该让应用程序崩溃并记录原因。静态初始化程序中的失败通常意味着环境存在严重错误,您不太可能从中恢复。另外,据我所知,一旦类加载失败,它就无法再次被同一个 ClassLoader 加载。

也就是说,如果您想在警报中向用户显示错误,即使错误发生在 JavaFX 运行时初始化之前,您也需要将错误保存在某处。然后,启动 JavaFX 后,检查存储错误的位置并显示它们。例如:

Main.java:

import javafx.application.Application;

public class Main {

  public static void main(String[] args) {
    // an "error" before JavaFX is launched
    App.notifyUserOfError(new RuntimeException("OOPS!"));
    Application.launch(App.class, args);
  }
}

应用程序.java:

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayDeque;
import java.util.Objects;
import java.util.Queue;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class App extends Application {

  private static Queue<Throwable> errorQueue;
  private static App appInstance;

  public static synchronized void notifyUserOfError(Throwable throwable) {
    Objects.requireNonNull(throwable);
    if (appInstance == null) {
      if (errorQueue == null) {
        errorQueue = new ArrayDeque<>();
      }
      errorQueue.add(throwable);
    } else {
      if (Platform.isFxApplicationThread()) {
        appInstance.showErrorAlert(throwable);
      } else {
        Platform.runLater(() -> appInstance.showErrorAlert(throwable));
      }
    }
  }

  private static synchronized Queue<Throwable> setAppInstance(App instance) {
    if (appInstance != null) {
      throw new IllegalStateException();
    }
    appInstance = instance;

    var queue = errorQueue;
    errorQueue = null; // no longer needed
    return queue;
  }

  private Stage primaryStage;

  @Override
  public void start(Stage primaryStage) {
    this.primaryStage = primaryStage;

    var scene = new Scene(new StackPane(new Label("Hello, World!")), 600, 400);
    primaryStage.setScene(scene);
    primaryStage.show();

    var errors = setAppInstance(this);
    if (errors != null) {
      // if non-null then should be non-empty
      do {
        showErrorAlert(errors.remove());
      } while (!errors.isEmpty());
      // possibly exit the application if you can't recover
    }
  }

  private void showErrorAlert(Throwable error) {
    var alert = new Alert(AlertType.ERROR);
    alert.initOwner(primaryStage);
    alert.setContentText(error.toString());

    var sw = new StringWriter();
    error.printStackTrace(new PrintWriter(sw));

    var area = new TextArea(sw.toString());
    area.setEditable(false);
    area.setFont(Font.font("Monospaced", 12));

    var details = new VBox(5, new Label("Stack trace:"), area);
    VBox.setVgrow(area, Priority.ALWAYS);
    alert.getDialogPane().setExpandableContent(details);

    alert.showAndWait();
  }
}

如果 JavaFX 尚未初始化,上面的代码会将错误放入队列中。在 start 方法结束时,将检查队列是否有任何错误,并将它们一个接一个地显示给用户。如果 JavaFX 已经初始化,则错误会立即显示给用户。

关于java - 静态初始化程序中的异常处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60876464/

相关文章:

JavaFX - 如何识别 ScrollBar 在 TableView 中的位置

java - 切换按钮 .isSelected() 为 true,但在 JavaFX 中视觉上没有变化

java - 硬件递归分而治之算法

java - 如何在 GWT Java 中获取当前工作目录

Java plist解析: how to determine if an NSObject is an array or a dictionary

java - 如果 kafka 消费者指定的偏移量不存在于 Broker 中,会发生什么情况?

JavaFX:滚动 Pane 不适合父级

javaFx 单选按钮和文本字段用户选择和用户输入

javafx - 我如何知道 TableView 是否为空?

java - 我应该在 throws 规范中声明未经检查的异常吗?