I have multiple CompletableFuture
CompletableFuture<String> comp1 = CompletableFuture.supplyAsync(() -> ...);
CompletableFuture<String> comp2 = CompletableFuture.supplyAsync(() -> ...);
...
CompletableFuture<String> compN = CompletableFuture.supplyAsync(() -> ...);
I need something like
CompletableFuture<Object> firstResult = CompletableFuture.anyOf(comp1, comp2, ..., compN);
but this returns the result from the first one that completes.
I want to have something that returns the first non-null result from the first one that completes. Is it possible?
There is no helper function in CompletableFuture
that returns first future to complete with a non-null value.
You can implement your own:
public static <T> CompletableFuture<T> anyNotNull(Collection<CompletableFuture<? extends T>> cfs) {
var cfsCopy = new ArrayList<>(cfs);
if (cfsCopy.isEmpty()) {
return CompletableFuture.failedFuture(new NoSuchElementException("No futures provided"));
}
var result = new CompletableFuture<T>();
var remaining = new AtomicInteger(cfsCopy.size());
for (CompletableFuture<? extends T> cf : cfsCopy) {
cf.whenComplete((v, ex) -> {
if (result.isDone()) return;
if (Objects.nonNull(v)) {
result.complete(v);
return;
}
if (remaining.decrementAndGet() == 0) {
result.completeExceptionally(new NoSuchElementException("No future completed with a non-null value"));
}
});
}
return result;
}
Few notes about the code:
Possible changes of the code that could make sense. Some of them are inspired by implementation of CompletableFuture.anyOf
:
whenComplete
varargs
instead of a Collection
parameter