Search code examples
javajava-8completable-futurecompletion-stage

How to combine multiple CompletionStage responses of type List(for me) or some other in java


I am trying to create multiple CompletionStage of type List, eg. CompletionStage<List<Car>>. And at the end I want to merge all the responses of type <List<Car>> in to one List in one CompletionStage.

CompletionStage<List<Car>> completionStageOne= carClientOne.getCarList();
CompletionStage<List<Car>> completionStageTwo= carClientTwo.getCarList();
CompletionStage<List<Car>> completionStageThree= carClientThree.getCarList();

So Here, suppose I have 3 different services which will give me different list of car as in response form of CompletionStage<List<Car>>

Now I am trying to combine them and creating one common list of cars and here I am getting the problem. I am using the below code to combine the result

CompletionStage<List<Car>> completionStageOneTwo = completionStageOne
.thenCombine(completionStageTwo,(x, y) -> Stream.concat(x.stream(), y.stream()).collect(Collectors.toList()));

//above will work but if I add the third one then it will not. 

CompletionStage<List<Car>> completionStageFinal = completionStageOneTwo
.thenCombine(completionStageThree,(x, y) -> Stream.concat(x.stream(), y.stream()).collect(Collectors.toList())); 

and at the end I am doing

List<Car> finalList = completionStageFinal.toCompletableFuture().get();

So what I am doing wrong? How can I combine this three? Am I blocking something?

Note: I already checked this answer from Holger, but not able to figure out how to use concat there.


Solution

  • Let me show you an example. I will show how to use CompletableFuture.AllOf(...) which allow waiting for all of the futures.

        // create promises to get cars
        CompletableFuture<List<String>> cars1 = CompletableFuture.completedFuture(Arrays.asList("BMW", "Alfa"));
        CompletableFuture<List<String>> cars2 = CompletableFuture.completedFuture(Collections.singletonList("WV"));
        CompletableFuture<List<String>> cars3 = CompletableFuture.completedFuture(Collections.singletonList("FIAT"));
    
        // collect promises just for convenience
        List<CompletableFuture<List<String>>> allFutures = Arrays.asList(cars1, cars2, cars3);
    
        // wait until all cars will be obtained
        CompletableFuture<List<String>> listCompletableFuture =
                CompletableFuture.allOf(cars1, cars2, cars3)
                .thenApply(avoid -> allFutures  //start to collect them
                        .stream()
                        .flatMap(f -> f.join().stream()) //get List from feature. Here these cars has been obtained, therefore non blocking
                        .collect(Collectors.toList())
        );
    
        // there are here
        listCompletableFuture.join().forEach(System.out::println);
    

    Output:

    BMW
    Alfa
    WV
    FIAT