Обработка исключений в инициализаторе stati c - PullRequest
0 голосов
/ 27 марта 2020

Обычно я обрабатываю свои исключения, показывая некоторые пользовательские предупреждения (JavaFX) с подробностями, но среда выполнения JavaFX вообще не инициализируется, когда запускается инициализатор stati c моего класса.

Есть ли способ обработать такое исключение, не печатая его содержимое для вывода как животное?

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

}

1 Ответ

0 голосов
/ 27 марта 2020

Первый консьерж, если вы не хотите, чтобы приложение просто взламывало sh и регистрировало причину. Сбой в инициализаторе stati c обычно означает, что со средой что-то серьезно не так, что вы вряд ли сможете восстановить. Кроме того, насколько я знаю, когда класс не загружается, он не может быть снова загружен тем же 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 уже инициализирован, то ошибка немедленно отображается пользователю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...