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 (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:
whenCompletevarargs instead of a Collection parameterIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With