У меня такое ощущение, что я неправильно использую ЗавершенныйБудущее API.
При вызове CompletableFuture.exceptionally() я обычно обнаруживаю, что мне нужно вызвать другой асинхронный процесс, а это означает, что exceptionally() возвращает CompletableFuture<CompletableFuture<T>> вместо CompletableFuture<T>. Затем я возвращаю результат с помощью thenCompose(x -> x).
Вот конкретный пример:
CompletableFuture<Void> listenersNotified = CompletableFuture.supplyAsync(() ->
{
int result = expensiveOperation();
List<CompletionStage<Void>> futures = new ArrayList<>();
for (EventListener listener: listeners)
listener.onSuccess(result);
return futures;
}).thenCompose(futures -> CompletableFuture.allOf(futures)).
exceptionally((exception) ->
{
List<CompletionStage<Void>> futures = new ArrayList<>();
for (EventListener listener: listeners)
futures.add(listener.onError(result));
return CompletableFuture.allOf(futures);
}).thenCompose(x -> x);
Я понимаю, что в приведенном выше примере можно return futures изнутри exceptionally() и переместить thenCompose() после exceptionally(), и это будет работать, но в реальной жизни я не всегда хочу применять ту же функцию к результату thenSupply() как результат exceptionally() . Я хочу, чтобы каждый раздел заботился о преобразовании своего собственного возвращаемого типа из CompletableFuture в синхронное значение.
Есть ли способ избежать этого?




Не думаю, что этого всегда можно избежать.
thenCompose()- это сочинять эквивалентthenApply(). Чтобы избежать этого во всех случаях, нам понадобятся эквиваленты сочинять для всех других методов, принимающих аргументFunctionилиBiFunction, то естьapplyToEither(),exceptionnally(),handle(),thenCombine()со всеми их перегрузками*Async(). Это означало бы как минимум 12 новых методов, и я думаю, что они не хотели раздувать API, когда вы можете просто использовать один из тех, за которым следуетthenCompose(x - x). Я согласен, что это было бы удобно, особенно для обработки исключений.