1

Given a collection of futures

final Collection<CompletableFuture<X>> futures = ...;
final CompletableFuture<Collection<X>> joined = ???

How to produce a future for a collection with all values combined together, without calling join?

Eugene
  • 117,005
  • 15
  • 201
  • 306
andreoss
  • 1,570
  • 1
  • 10
  • 25
  • What's your logic for combining those individual futures? I mean, if one of those `CompletableFuture` were to fail or timeout, how should it affect the combined `CompletableFuture>`? – ernest_k Feb 23 '21 at 00:47

1 Answers1

1

The solution is to

  1. Convert Collection<CompletableFuture<X>> to Collection<CompletableFuture<Collection<X>>>
  2. Reduce on this collection using CompletableFuture.completedFuture(Collections.emptyList()) as initial value.
final CompletableFuture<Collection<X>> joined = 
                futures
                .stream()
                .map(f -> f.thenApply(value -> (Collection<X>)Collections.singletonList(value)))
                .reduce(
                        CompletableFuture.completedFuture(Collections.emptyList()), 
                        (f, g) -> 
                            f.thenCompose(
                                xs -> g.thenApply(
                                     ys -> Stream
                                               .of(xs, ys)
                                               .flatMap(Collection::stream)
                                               .collect(Collectors.toList()))
                                )
                            );
andreoss
  • 1,570
  • 1
  • 10
  • 25
  • This is a good method – TongChen Feb 23 '21 at 01:28
  • what you have shown here is pretty much the same thing as [here](https://stackoverflow.com/a/32667118/1059372), from the duplicate – Eugene Feb 23 '21 at 04:06
  • the problem with this btw, is that `thenCompose/thenApply` can be easily executed in the `main` thread, but otherwise I think this looks nice. – Eugene Feb 23 '21 at 04:14