2017-09-05 1 views
2

Die Idee der Verwendung CompletableFuture ist, weil es eine Kette bietet, während die ersten paar Schritte Bohnen einkapseln, bevor der letzte Schritt es verwendet. Da in diesen Schritten jede Ausnahme auftreten kann, wird exceptionally verwendet, um Fehler zu behandeln. Allerdings akzeptiert exceptionally nur Throwable Argument und bis jetzt habe ich keinen Weg gefunden, diese eingekapselten Bohnen zu greifen.ComplectableFuture bricht die Arbeitskette ausnahmsweise

CompletableFuture.supplyAsync(this::msgSource) 
      .thenApply(this::sendMsg).exceptionally(this::errorHandler).thenAccept(this::saveResult) 
public List<Msg> msgSource() // take message from somewhere. 
public List<Msg> sendMsg(List<Msg>) // exceptions may happen like 403 or timeout 
public List<Msg> errorHandler() // set a success flag to false in Msg. 
public void saveResult(List<Msg>) // save send result like success or false in data center. 

Im obigen Beispiel sind Kommentare der Arbeitsablauf. Da jedoch errorHandler weder List<Msg> akzeptiert noch weitergibt, ist die Kette also kaputt. Wie bekomme ich die Rückkehr von msgSource?

EDIT

public class CompletableFutureTest { 

    private static Logger log = LoggerFactory.getLogger(CompletableFutureTest.class); 
    public static void main(String[] args) { 
     CompletableFutureTest test = new CompletableFutureTest(); 
     CompletableFuture future = new CompletableFuture(); 
     future.supplyAsync(test::msgSource) 
      .thenApply(test::sendMsg).exceptionally(throwable -> { 
      List<String> list = (List<String>) future.join(); // never complete 
      return list; 
     }).thenAccept(test::saveResult); 
     try { 
      future.get(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } catch (ExecutionException e) { 
      e.printStackTrace(); 
     } 
    } 

    private List<String> saveResult(List<String> list) { 
     return list; 
    } 

    private List<String> sendMsg(List<String> list) { 
     throw new RuntimeException(); 
    } 

    public List<String> msgSource() { 
     List<String> result = new ArrayList<>(); 
     result.add("1"); 
     result.add("2"); 
     return result; 
    } 
} 

enter image description here

Antwort

3

A Kette impliziert, dass jeder Knoten, d.h. Vollendungsstufe, um das Ergebnis der vorherigen verwendet. Wenn jedoch die vorherige Stufe mit einer Ausnahme fehlgeschlagen ist, gibt es kein solches Ergebnis. Es ist eine spezielle Eigenschaft Ihrer Stufe sendMsg, dass ihr Ergebnis genau dem Wert entspricht, den sie von der vorherigen Stufe erhalten hat, aber dies hat keinen Einfluss auf die Logik und das API-Design. Wenn sendMsg mit einer Ausnahme fehlschlägt, führt dies zu keinem Ergebnis, das der Ausnahmebehandler verwenden könnte.

Wenn Sie das Ergebnis der msgSource Bühne im Ausnahmefall verwenden möchten, haben Sie keine lineare Kette mehr. Aber CompletableFuture erlaubt beliebige Abhängigkeitsgraphen zu modellieren, nicht nur lineare Ketten, so können Sie es ausdrücken wie

CompletableFuture<List<Msg>> source = CompletableFuture.supplyAsync(this::msgSource); 
source.thenApply(this::sendMsg) 
     .exceptionally(throwable -> { 
      List<Msg> list = source.join(); 
      for(Msg m: list) m.success = false; 
      return list; 
     }) 
     .thenAccept(this::saveResult); 

Allerdings gibt es keinen semantischen Unterschied noch Vorteil gegenüber

CompletableFuture.runAsync(() -> { 
    List<Msg> list = msgSource(); 
    try { 
     list = sendMsg(list); 
    } catch(Throwable t) { 
     for(Msg m: list) m.success = false; 
    } 
    saveResult(list); 
}); 

, die die gleiche Logik zum Ausdruck bringt als normaler Code-Fluss.

+0

würde das nicht 'success = false 'für alle' Msg' setzen, wenn eine einzige fehlgeschlagen ist? – Eugene

+2

@Eugene: sicher. Wenn 'sendMsg (List )' fehlschlägt, bedeutet dies einen Fehler für die gesamte Liste. So wird der Code der Frage entworfen, der für die Verwendung von 'CompletableFuture' gilt, sowie für die Methoden, die eine' List' empfangen und zurückgeben. – Holger

+0

Wenn "ausnahmsweise" alle Manipulationen vergißt, die seine früheren Arbeiten an Nachrichten verübten, wäre seine Rückkehr sehr nutzlos. Aber Ihr erstes Codesegment zeigt, dass es eine Möglichkeit gibt, die frühere Arbeit tatsächlich zu entfernen, nur unter der Voraussetzung, dass man vorausahnt, welche Arbeit die Ausnahme verursacht *. Was ich dachte, war das Argument (in diesem Fall die 'Liste ') der Funktion, die die Ausnahme in 'ausnahmsweise' auslöst. Manchmal könnte diese Kette länger sein und versuchen, in jedem von ihnen einzufangen, könnte meistens bedeutungslos sein. – Tiina

Verwandte Themen