Задача JavaFX, похоже, потребляет исключения. Это ошибка или функция?

Рассмотрим этот код:

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, почему исключение не распространяется на обработчик исключений?

Ответы

Ответ 1

Функция, Задача поддерживает свойство exception. Идея состоит в том, что при возникновении исключения задачи прерываются, и можно спросить, какое исключение было выбрано. В этом отношении задача была задумана как квази-пакетное задание, работающее в фоновом режиме и, возможно, без умолку.

Это отражает также немного асинхронного поведения; где исключение можно было бы обработать. Не в том месте, где был вызван start.

Ответ 2

Внутри метода Task.call() просто выделите исключение и добавьте ChangeListener к задаче, подобной этой:

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

Затем, после того как задача завершилась с исключением, вы получите уведомление слушателем, какое исключение было отправлено во время выполнения. Вы можете легко обменивать строку ex.printStackTrace(); с помощью Alert, если вы находитесь в потоке исполнения JavaFX.

Ответ 3

Возможно, немного поздно, но вы можете напечатать само бросающееся:

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-приложении, но это не сработало).