Я не верю, что CompletionStage
или CompletableFuture
предоставляют какой-либо один метод для этого.Однако сочетание handle
с thenCompose
должно делать то, что вы хотите, если я правильно понимаю ваши требования.
A handle
этап выполняется независимо от того, завершился ли родительский этап нормально или исключительно, и дает вам доступ крезультат или ошибка соответственно.На этом этапе вы можете вернуть еще один CompletionStage
, который будет либо завершен нормально, либо исключительно, в зависимости от того, какие аргументы получает этап handle
.
handle((T result, Throwable error) -> {
if (error != null) {
return CompletableFuture.<T>failedStage(error);
} else {
return processResult(result); // returns CompletionStage<T>
}
});
Теперь у вас есть CompletionStage<CompletionStage<T>>
.Теперь мы выполняем операцию плоской карты, вызывая thenCompose
:
thenCompose(Function.identity());
, что дает нам CompletionStage<T>
.Это CompletionStage<T>
будет тем экземпляром, который был возвращен handle
.Если этот экземпляр был ошибочным этапом, то исключение все еще распространяется;в противном случае результат передается на любой этап, зависящий от этапа thenCompose
, и обработка продолжается в обычном режиме.
Это можно увидеть на следующем примере:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
public class Main {
public static void main(String[] args) {
methodThatReturnsCompletionStage()
.handle((result, error) -> {
if (error != null) {
return CompletableFuture.<String>failedStage(error);
} else {
return processResult(result);
}
})
.thenCompose(future -> {
System.out.println("#thenCompose invoked");
return future; // Identity function
})
.thenApply(result -> {
System.out.println("#thenApply invoked");
return result; // Identity function (exists to show intermediary stage)
})
.whenComplete((result, error) -> {
System.out.println("#whenComplete invoked");
if (error != null) {
error.printStackTrace(System.out);
} else {
System.out.println(result);
};
});
}
private static CompletionStage<String> methodThatReturnsCompletionStage() {
return CompletableFuture.completedStage("Hello");
// return CompletableFuture.failedStage(new RuntimeException("OOPS"));
}
private static CompletionStage<String> processResult(String result) {
return CompletableFuture.completedFuture(result + ", World!");
}
}
Это приведет ккаждая вызванная стадия и вывод Hello, World!
.Но если вместо этого переключить methodThatReturnsCompletionStage()
, чтобы вернуть сбойный этап, thenApply
пропускается (потому что будущее провалилось), и исключение составляет whenComplete
(который, как и handle
, вызывается как для обычного, так и исключительного).завершение).
Примечание: Все вышеперечисленное использует интерфейс CompletionStage
напрямую, но использование CompletableFuture
работает так же (и может быть предпочтительнее).