2015-11-30 11 views
13

Jeśli mają 2 CompletionStages mogę połączyć je z thenCombine metoda:Jak połączyć 3 lub więcej etapów realizacji?

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

Jeśli mam 3 lub więcej CompletionStages mogę zrobić łańcuch thenCombine metod, ale muszę używać tymczasowych obiektów do przekazania wyników. Na przykład, o to rozwiązanie wykorzystujące Pair i Triple z pakietu org.apache.commons.lang3.tuple:

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)); 

Czy istnieje lepszy sposób na połączenie wyników z wielu CompletionStages?

+2

Nie rozumiem, co chce zrobić. Jaka jest twoja metoda "łączenia"? Jaki jest jego cel? Co chcesz zrobić z 'CompletionStage's? Kto jest konsumentem na końcu? Jaki powinien być wynik, jaki otrzymują? –

+0

@SotiriosDelimanolis, "Combine" to funkcja pobierająca 4 parametry i zwracająca 1 typu "Combined". Konsumentem może być na przykład inna funkcja przyjmująca parametr "Połączony" jako parametr i zwracająca inny "CompletionStage", który jest wywoływany za pomocą 'combinedDataCompletionStage.thenCompose (...)'. –

Odpowiedz

17

Jedynym sposobem na połączenie wielu etapów, które dobrze się skalują z rosnącą liczbą etapów, jest użycie CompletableFuture. Jeśli twoje CompletionStage s nie są CompletableFuture s nadal można przekonwertować je przy użyciu .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())); 

ta zawiera więcej niż szablonowe połączenie dwóch etapach poprzez thenCombine ale boilerplate nie rosną podczas dodawania do niej kolejne etapy.


Zauważ, że nawet z oryginalnego thenCombine podejściu, nie trzeba się Triple, A Pair jest wystarczająca:

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

Mimo to, nie skaluje się dobrze, jeśli chcesz połączyć więcej gradacja.


W-między rozwiązanie (dotyczące złożoności) może być:

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

To prostsze w swej strukturze, ale nadal nie działa dobrze skalować z bardziej kilku etapach.

2

Holger's third answer można nieco krótszy:

CompletionStage<Combined> combinedDataCompletionStage = aCompletionStage.thenCompose(
    a -> bCompletionStage.thenCompose(
     b -> cCompletionStage.thenCombine(dCompletionStage, 
      (c, d) -> combine(a, b, c, d)))); 
Powiązane problemy