Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CompletableFuture: like anyOf() but return a new CompletableFuture that is completed when any of the given CompletableFutures return not null

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?

like image 702
res1 Avatar asked Oct 21 '25 21:10

res1


1 Answers

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:

  • make a copy of the input collection to avoid issues if the caller mutates the list of passed futures
  • return a failed future if:
    • the collection is empty
    • all futures complete with null or exceptionally

Possible changes of the code that could make sense. Some of them are inspired by implementation of CompletableFuture.anyOf:

  • check for already completed futures with non-null results before attaching callbacks via whenComplete
  • cancel remaining futures once an acceptable result is found
  • accept varargs instead of a Collection parameter
  • log exceptions from futures that complete exceptionally instead of ignoring them
like image 86
Geba Avatar answered Oct 23 '25 09:10

Geba



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!