【问题标题】:JavaFX's task seem to consume exceptions. Is it a bug or a feature?JavaFX 的任务似乎消耗异常。它是错误还是功能?
【发布时间】:2014-09-16 07:57:51
【问题描述】:

考虑这段代码:

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,为什么不将异常传播到异常处理程序?

【问题讨论】:

    标签: java javafx-8


    【解决方案1】:

    Task.call() 方法中,只需抛出异常并将ChangeListener 添加到任务中,如下所示:

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

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

    【讨论】:

      【解决方案2】:

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

      这也反映了一些异步行为; 哪里可以处理异常。 不在调用start的地方。

      【讨论】:

      • 有没有办法重新抛出异常而不将其包装在 RuntimeException 中?我试过throw task.getException();,但编译器只是尖叫。
      • 我对 JavaFX 的了解非常有限。
      • 不,你不能。正如您在文档 (docs.oracle.com/javafx/2/api/javafx/event/EventHandler.html) 中看到的,Eventhandler 的句柄方法不会引发任何异常。您也不能将 Exception 给周围的块以重新抛出,因为该块已因异步调用而离开。
      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

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

        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 应用程序中获得相同的输出,但没有成功)。

        【讨论】:

        • 没有好的解决方案,因为我必须“猜测”异常......好吧,如果你知道你的代码,你可能知道它是什么异常,但情况并非总是如此。
        猜你喜欢
        • 2011-02-28
        • 1970-01-01
        • 2013-05-08
        • 1970-01-01
        • 1970-01-01
        • 2015-01-20
        • 2021-02-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多