Удивительное поведение Java 8 CompletingFuture исключительно метод
Я столкнулся с странным поведением метода Java 8 CompletableFuture.exceptionally. Если я выполню этот код, он отлично работает и печатает java.lang.RuntimeException
CompletableFuture<String> future = new CompletableFuture<>();
future.completeExceptionally(new RuntimeException());
future.exceptionally(e -> {
System.out.println(e.getClass());
return null;
});
Но если я добавлю еще один шаг в будущую обработку, например thenApply
, тип исключения изменится на java.util.concurrent.CompletionException
с исходным исключением, заключенным внутри.
CompletableFuture<String> future = new CompletableFuture<>();
future.completeExceptionally(new RuntimeException());
future.thenApply(v-> v).exceptionally(e -> {
System.out.println(e);
return null;
});
Есть ли причина, почему это должно происходить? На мой взгляд, это довольно удивительно.
Ответы
Ответ 1
Это поведение указано в документации по классу CompletionStage
(четвертая марка):
Метод handle
дополнительно позволяет сцене вычислить результат замены, который может обеспечить дальнейшую обработку другими зависимыми этапами. Во всех остальных случаях, если этапное вычисление резко прекращается с (неконтролируемым) исключением или ошибкой, то все зависимые этапы, требующие его завершения, также выполняются исключительно с помощью CompletionException
, за исключением исключения.
Не удивительно, если вы считаете, что можете захотеть узнать, на сцене вы вызвали exceptionally
on, failed или один из его прямых или косвенных предпосылок.
Ответ 2
да, поведение ожидается, но если вы хотите исходное исключение, которое было выбрано с одного из предыдущих этапов, вы можете просто использовать this-
CompletableFuture<String> future = new CompletableFuture<>();
future.completeExceptionally(new RuntimeException());
future.thenApply(v-> v).exceptionally(e -> {
System.out.println(e.getCause()); // returns a throwable back
return null;
});