I want to implement a hybrid of CompletableFuture.allOf() and CompletableFuture.anyOf() where the returned future completes successfully as soon as
This question is actually very similar to Replace Futures.successfulAsList with Java 8 CompletableFuture?
Although the question is not exactly the same, the same answer (from myself) should satisfy your needs.
You can implement this with a combination of allOf() and chaining each input future with an exceptionally() that would make the future returned by allOf() immediately fail:
CompletableFuture<String> a = …, b = …, c = …;
CompletableFuture<Void> allWithFailFast = CompletableFuture.allOf(a, b, c);
Stream.of(a, b, c)
.forEach(f -> f.exceptionally(e -> {
allWithFailFast.completeExceptionally(e);
return null;
}));
I believe this will do the job:
/**
* @param arrayOfFutures an array of futures to wait on
* @return a {@code CompletableFuture} that completes successfully once all elements have completed successfully, or completes
* exceptionally after any of the elements has done the same
* <br>{@code @throws NullPointerException} if {@code arrayOfFutures} is null
*/
public CompletableFuture<Void> waitForAllButAbortOnFirstException(CompletableFuture<?>... arrayOfFutures)
{
if (arrayOfFutures == null)
return CompletableFuture.failedFuture(new NullPointerException("arrayOfFutures may not be null"));
if (arrayOfFutures.length == 0)
return CompletableFuture.completedFuture(null);
return CompletableFuture.anyOf(arrayOfFutures).
thenApply(unused ->
{
// Remove any futures that completed normally and try again
return Arrays.stream(arrayOfFutures).
filter(element -> !element.isDone() || element.isCompletedExceptionally()).
toArray(CompletableFuture[]::new);
}).
thenCompose(remainingFutures -> waitForAllButAbortOnFirstException(remainingFutures));
}