2016-11-21 6 views
1

ich jetzt in ein wenig Verwirrung bin, so habe ich eine Methode, die CompletableFuture<List<A>>CompletableFutures und Filterung basierend auf Werten, die im Inneren sind

innerhalb der Methode ist zurückgeben sollte:

CompletableFuture<List<String>> toReturn = asyncCall().thenApply(....) 
.thenCompose(listOfStuff -> convertToList(listOfStuff.stream().map(
    key -> asyncCall2(key) 
     .thenApply(optionalValue -> optionalValue.orElse(null)) 
).collect(Collectors.toList())); 

und convertToList() verbindet einfach Futures zu konvertieren CompletableFuture<List<ComputableFuture<A>>> in

Grundsätzlich meine Absicht ist Null-Werte filtern, die aus optionalValue.orElse(null) entstehen Und es wäre einfach, Filter vor coll zu tun Alles in der letzten Zeile auflisten, aber wenn ich es gerade vor .collect benutze es funktioniert über CompletableFutures

Ich vermute, es gibt eine Menge von Umstrukturierungen, die ich in meinem Code tun kann.

EDIT:

private<T> CompletableFuture<List<T>> convertToList(List<CompletableFuture<T>> toConvert) { 
    return CompletableFuture.allOf(toConvert.toArray(new CompletableFuture[toConvert.size()])) 
      .thenApply(v -> toConvert.stream() 
        .map(CompletableFuture::join) 
        .collect(Collectors.toList()) 
      ); 
} 
+0

Verwenden Sie 'Stream.of()' und 'Stream.empty()'? – akalikin

+0

Rufen Sie '.orElse (null)' nicht auf, dann müssen Sie nicht nach 'null' testen. Also wäre der Parametertyp von 'convertToList'' List >> 'und es kann einfach ein' .filter (Optional :: isPresent) .map (Optional :: get) 'nach dem' Join' ... – Holger

+0

@ Holger ja, es ist eine Option zu filtern (entweder auf Optionals oder Null-Werte) in 'ConvertToList', würde ich gerne alles an einer Stelle tun, und' convertToList' kann eine universelle Dienstprogrammfunktion sein – Amir

Antwort

1

Der beste Weg wäre wahrscheinlich convertToList() zu ändern, so dass es nicht eine Zukunft der Liste zurückkehrt, aber der Strom statt:

private <T> CompletableFuture<Stream<T>> convertToFutureOfStream(List<CompletableFuture<T>> toConvert) { 
    return CompletableFuture.allOf(toConvert.stream().toArray(CompletableFuture[]::new)) 
      .thenApply(
        v -> toConvert.stream() 
          .map(CompletableFuture::join) 
      ); 
} 

Dies wird mehr wiederverwendbar da die Methode eine bessere Verkettung ermöglicht und den Anrufer nicht dazu zwingt, mit einer Liste zu arbeiten, während es immer noch möglich ist, eine Liste mit einer einfachen Sammlung zu erhalten.

können Sie dann auswählen, einfach diesen Strom leer optionals entfernen:

CompletableFuture<List<String>> toReturn = asyncCall() 
    .thenCompose(listOfStuff -> convertToFutureOfStream(
      listOfStuff.stream() 
        .map(this::asyncCall2) 
        .collect(Collectors.toList()) 
     ) 
     .thenApply(stream -> 
       stream.filter(Optional::isPresent) 
         .map(Optional::get) 
         .collect(Collectors.toList()) 
     ) 

    ); 

Sie können diese convertToFutureOfStream() durch etwas noch weiter verbessern zu ändern als auch einen Stream als Argument zu nehmen:

private <T> CompletableFuture<Stream<T>> convertToFutureOfStream(Stream<CompletableFuture<T>> stream) { 
    CompletableFuture<T>[] futures = stream.toArray(CompletableFuture[]::new); 
    return CompletableFuture.allOf(futures) 
      .thenApply(v -> Arrays.stream(futures).map(CompletableFuture::join)); 
} 

(Dies führt leider zu einer ungeprüften Zuweisungswarnung wegen der Anordnung der generischen Typen)

Welches gibt dann

CompletableFuture<List<String>> toReturn = asyncCall() 
    .thenCompose(listOfStuff -> convertToFutureOfStream(
       listOfStuff.stream().map(this::asyncCall2) 
      ) 
     .thenApply(stream -> 
       stream.filter(Optional::isPresent) 
         .map(Optional::get) 
         .collect(Collectors.toList()) 
     ) 

    ); 
Verwandte Themen