Well, it all depends on when you need the result. If you want it to be consistent, this below is still worthy, since its lazy. But it will boil during terminal operation (say during collect ).
public static Stream<FlightInfo> getResults(String origin,List<String> destinations) { final String uri = "https://api.searchflight.com/"; return destinations.stream().map(destination -> { RestTemplate restTemplate = new RestTemplate(); String params = getParams(origin,destination); FlightInfo result = restTemplate.postForObject(uri+params,FlightInfo.class); return result; }) }
Or I'll do it with destinations.stream().parallel() if I can. This is a reasonable result in most cases. But still he will not start processing it in parallel until the moment when you call the terminal operation for it. Which absolutely makes sense.
But it seems to me that you want a consumer producer. For what:
public static CompletableFuture<List<FlightInfo>> getResults(String origin,List<String> destinations) { final String uri = "https://api.searchflight.com/"; List<CompletableFuture<FlightInfo>> collect = destinations .stream() .map(destination -> CompletableFuture.supplyAsync(() -> { RestTemplate restTemplate = new RestTemplate(); String params = getParams(origin,destination); FlightInfo result = restTemplate.postForObject(uri+params,FlightInfo.class); return result; })).collect(Collectors.toList()); return sequence(collect);
For simplicity , line-1 you can simply return collect instead of sequence(collect) . You can then iterate over the list to get each value.
But with sequence , you have one CompletableFuture object that you can worry about, after which you can check the values immediately after completion.
Jatin source share