JavaFX的任务似乎消耗了异常。这是一个错误还是一个功能?

时间:2014-09-16 07:57:52

标签: java javafx-8

考虑以下代码:

Thread.setDefaultUncaughtExceptionHandler((Thread t, Throwable e) -> {
    System.out.println("An exception occurred!");
});

// set the exception handler for the JavaFX application thread
Thread.currentThread().setUncaughtExceptionHandler((Thread t, Throwable e) -> {
    System.out.println("An exception occurred!");
});

Task<?> task = new Task() {
    @Override
    public Void call() throws Exception {
        throw new RuntimeException("foobar");
    };
};

new Thread(task).start();

如果我们运行代码,运行时异常永远不会触发默认的异常处理程序,而是由任务使用。解决这个问题的唯一方法就是在task.setOnFailed中重新抛出异常:

task.setOnFailed((WorkerStateEvent t) -> {
    throw new RuntimeException(task.getException());
});

由于JavaFX 8现在支持UncaughtExceptionHandler,为什么不将异常传播到异常处理程序?

4 个答案:

答案 0 :(得分:8)

Task.call()方法内部,只需抛出异常并向此任务添加ChangeListener,如下所示:

task.exceptionProperty().addListener((observable, oldValue, newValue) ->  {
  if(newValue != null) {
    Exception ex = (Exception) newValue;
    ex.printStackTrace();
  }
});

然后,在任务因异常而失败后,监听器会通知您在执行期间抛出了哪个异常。如果您在JavaFX执行线程中,则可以轻松地将行ex.printStackTrace();Alert交换。

答案 1 :(得分:6)

可能有点迟,但你可以打印throwable本身:

task.setOnFailed(new EventHandler<WorkerStateEvent>() {
    @Override
    public void handle(WorkerStateEvent arg0) {
        Throwable throwable = task.getException(); 
        throwable.printStackTrace();
    }
}

无论如何都会抛出异常,但您可以使用它向用户显示或记录它。

答案 2 :(得分:5)

功能,任务本身维护exception属性。这个想法是,当抛出异常时,任务失败,并且可能会询问抛出了哪个异常。在这方面,Task被认为是一个准批处理作业,在后台运行,可能会默默地失败。

这也反映了异步行为的一点点; 其中可以处理异常。 不在start被调用的地方。

答案 3 :(得分:2)

我知道这个问题很老,但是我搜索了一个答案,并没有找到很多关于这个主题的内容。如果您愿意,我认为您可以重新抛出异常。以下是示例代码:

public class Main extends Application {

@Override
public void start(Stage stage) {

    Task<Void> task = new Task<Void>() {
        @Override
        protected Void call() throws Exception {
            throw new IndexOutOfBoundsException();
        }
    };
    task.setOnSucceeded(evt -> System.out.println("Task succeeded!"));
    task.setOnCancelled(evt -> System.out.println("Task cancelled!"));
    task.setOnFailed(evt -> {
        System.out.println("Task failed!");
        if (task.getException() instanceof IndexOutOfBoundsException) {
            System.out.println("...with an IndexOutOfBoundsException");
        } else if (task.getException() instanceof NumberFormatException) {
            System.out.println("...with a NumberFormatException");
        } else {
            System.out.println("...with another, unexpected execption");
        }
    });

    VBox box = new VBox();
    Scene scene = new Scene(box, 200, 200);
    stage.setScene(scene);
    stage.setTitle("Thread Example");
    stage.show();

    new Thread(task).start();

}

public static void main(String[] args) {
    launch(args);
}
}
  

控制台 - 输出:   任务失败!   ...使用IndexOutOfBoundsException

如果在任务中抛出异常,则任务最终处于“失败”状态。在setOnFailed方法中,您可以处理任务的失败。此方法中的所有代码都在JavaFX的应用程序线程上,但您可以通过task.getException()依赖任务的异常。此外,此代码仅适用于JavaFX(我试图在普通的Java应用程序中获得相同的输出,但它没有用完)。