Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to combine 3 or more CompletionStages?

If have 2 CompletionStages, I can combine them with thenCombine method:

CompletionStage<A> aCompletionStage = getA(); CompletionStage<B> bCompletionStage = getB(); CompletionStage<Combined> combinedCompletionStage =     aCompletionStage.thenCombine(bCompletionStage, (aData, bData) -> combine(aData, bData)); 

If I have 3 or more CompletionStages, I can make a chain of thenCombine methods, but I have to use temporary objects to pass results. For example, here is a solution using Pair and Triple from the org.apache.commons.lang3.tuple package:

CompletionStage<A> aCompletionStage = getA(); CompletionStage<B> bCompletionStage = getB(); CompletionStage<C> cCompletionStage = getC(); CompletionStage<D> dCompletionStage = getD();  CompletionStage<Combined> combinedDataCompletionStage =         aCompletionStage.thenCombine(bCompletionStage, (Pair::of))                 .thenCombine(cCompletionStage, (ab, c) ->                         Triple.of(ab.getLeft(), ab.getRight(), c))                 .thenCombine(dCompletionStage, (abc, d) ->                         combine(abc.getLeft(), abc.getMiddle(), abc.getRight(), d)); 

Is there a better way to combine results from multiple CompletionStages?

like image 970
Vladimir Korenev Avatar asked Nov 30 '15 17:11

Vladimir Korenev


People also ask

What is a Completable future?

What's a CompletableFuture? CompletableFuture is used for asynchronous programming in Java. Asynchronous programming is a means of writing non-blocking code by running a task on a separate thread than the main application thread and notifying the main thread about its progress, completion or failure.

What is CompletionStage in Java?

A stage of a possibly asynchronous computation, that performs an action or computes a value when another CompletionStage completes. A stage completes upon termination of its computation, but this may in turn trigger other dependent stages.


1 Answers

The only way to combine multiple stages that scales well with a growing number of stages, is to use CompletableFuture. If your CompletionStages aren’t CompletableFutures you may still convert them using .toCompletableFuture():

CompletableFuture<A> aCompletionStage = getA().toCompletableFuture(); CompletableFuture<B> bCompletionStage = getB().toCompletableFuture(); CompletableFuture<C> cCompletionStage = getC().toCompletableFuture(); CompletableFuture<D> dCompletionStage = getD().toCompletableFuture();  CompletionStage<Combined> combinedDataCompletionStage = CompletableFuture.allOf(     aCompletionStage, bCompletionStage, cCompletionStage, dCompletionStage)     .thenApply(ignoredVoid -> combine(         aCompletionStage.join(), bCompletionStage.join(),         cCompletionStage.join(), dCompletionStage.join()) ); 

This contains more boilerplate than combining two stages via thenCombine but the boilerplate doesn’t grow when adding more stages to it.


Note that even with your original thenCombine approach, you don’t need a Triple, a Pair is sufficient:

CompletionStage<Combined> combinedDataCompletionStage =     aCompletionStage.thenCombine(bCompletionStage, (Pair::of)).thenCombine(         cCompletionStage.thenCombine(dCompletionStage, Pair::of),         (ab, cd) -> combine(ab.getLeft(), ab.getRight(), cd.getLeft(), cd.getRight())); 

Still, it doesn’t scale well if you want to combine more stages.


An in-between solution (regarding complexity) might be:

CompletionStage<Combined> combinedDataCompletionStage = aCompletionStage.thenCompose(     a -> bCompletionStage.thenCompose(b -> cCompletionStage.thenCompose(         c -> dCompletionStage.thenApply(d -> combine(a, b, c, d))))); 

That’s simpler in its structure but still doesn’t scale well with more more stages.

like image 63
Holger Avatar answered Sep 24 '22 10:09

Holger