you can use this code, if the order of list is not important consider parallelizsing it
List<CompletableFuture<List<String>>> futureResponselist = new ArrayList<>();
futureResponselist.add(CompletableFuture.supplyAsync(() -> List.of("1" , "2")));
futureResponselist.add(CompletableFuture.supplyAsync(() -> List.of("3" , "4", "5")));
futureResponselist.add(CompletableFuture.supplyAsync(() -> List.of("6")));
List<String> result = futureResponselist
.stream()
.map(CompletableFuture::join)
.flatMap(List::stream)
.collect(Collectors.toList());
update: more general approach it is adopted from the Modern Java in Action
Executor executor =
Executors.newFixedThreadPool(5);
List<CompletableFuture<List<String>>> futureResponselist = new ArrayList<>();
futureResponselist.add(CompletableFuture.supplyAsync(() -> List.of("1" , "2"), executor));
futureResponselist.add(CompletableFuture.supplyAsync(() -> List.of("3" , "4", "5"), executor));
futureResponselist.add(CompletableFuture.supplyAsync(() -> List.of("6"), executor));
List<CompletableFuture<List<String>>> futureResult = futureResponselist
.stream()
.map(future -> future.thenApply(Function.identity())) // do some processing with list here we just return it but you can do something else
.map(future -> future.thenApply(Function.identity()))
.collect(Collectors.toList());
futureResult
.parallelStream()
.map(CompletableFuture::join)
.flatMap(List::stream)
.forEach(System.out::println); // do something when the result is ready here we just print it