簡體   English   中英

靜態初始化器中的異常處理

[英]Exception handling in static initializer

通常我通過顯示一些帶有詳細信息的自定義警報 (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,請檢查您存儲錯誤的位置並顯示它們。 例如:

主.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 已經被初始化,那么錯誤會立即顯示給用戶。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM