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);
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);
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).
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()));
}