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