2

I have a list of CompletableFuture instances.

List<CompletableFuture<String>> listOfFutures;

How is it to convert them to one future like this:

CompletableFuture<List<String>> futureOfList = convert(listOfFutures);
Filburt
  • 17,626
  • 12
  • 64
  • 115

2 Answers2

1

This is a monadic sequence operation. With the cyclops-monad-api (a library I wrote) you can write

   AnyM<Stream<String>> futureStream = AnyMonads.sequence(
              AsAnyMList.completableFutureToAnyMList(futures));

   CompletableFuture<Stream<String>> futureOfList = futureStream.unwrap();

When you call a terminal operation on the Stream inside futureOfList, e.g. to convert to a List, it will trigger the join() call on all the original futures, so should be used in a similar manner to join() itself.

    CompletableFuture<List<String>> completed = futureOfList.thenApply(
                  s->s.collect(Collectors.toList());

To write your own version specifically for CompletableFuture you could do something like this

 CompletableFuture<Stream<String>> futureOfList = CompletableFuture.completedFuture(1)
           .thenCompose(one->listOfFutures.stream()
                                         .map(cf->cf.join()));

Then to join

CompletableFuture<List<String>> completed = futureOfList.thenApply(
                s->s.collect(Collectors.toList());

See also this question and answer for a solution using allOf (which won't block any additional threads).

Community
  • 1
  • 1
John McClean
  • 5,225
  • 1
  • 22
  • 30
0

You can do it like this:

public static <T> CompletableFuture<List<T>> convert(List<CompletableFuture<T>> futures) {
    return futures.stream().
            map(f -> f.thenApply(Stream::of)).
            reduce((a, b) -> a.thenCompose(xs -> b.thenApply(ys -> concat(xs, ys)))).
            map(f -> f.thenApply(s -> s.collect(toList()))).
            orElse(completedFuture(emptyList()));
}
Yaroslav
  • 81
  • 1
  • 3