2017-09-05 7 views
2

CompletableFutureを使用するという考え方はチェーンを提供するからです。最初のいくつかのステップでは、最後のステップで使用する前にBeanをカプセル化します。これらのステップでは例外が発生する可能性があり、エラー処理にはexceptionallyが使用されるためです。しかし、exceptionallyThrowable引数しか受け付けていませんが、これまでカプセル化されたBeanを取得する方法が見つかりませんでした。CompletableFutureが例外的にワークチェーンを壊す

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. 

上記の例では、コメントは作業フローです。ただし、errorHandlerList<Msg>を受け付けていないため、チェーンが壊れています。 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

答えて

3

は各ノード、すなわち完了段階は、前の結果を使用することを意味します。しかし、前のステージが例外で失敗した場合、そのような結果はありません。 sendMsgステージの特別なプロパティです。その結果は前のステージから受け取った値と同じですが、ロジックやAPIデザインには影響しません。 sendMsgが例外で失敗した場合、例外ハンドラが使用できる結果はありません。

例外的なケースでmsgSourceステージの結果を使用する場合は、これ以上リニアチェーンがありません。しかしCompletableFuture任意の依存グラフ、ちょうどリニアないチェーンをモデル化することができないので、あなたはしかし

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

のようにそれを表現することができ、同じロジックを表現

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

に対して何ら意味上の違いも利点がありません通常のコードフローと同じです。

+0

単一のメッセージが失敗した場合、すべての 'Msg'に対して' success = false'を設定しませんか? – Eugene

+2

@Eugene:sure。 'sendMsg(List )'が失敗すると、それはリスト全体の失敗を意味します。これは、 'CompletableFuture'の使い方や、' List'を受け取って返すメソッドにも適用される質問のコードの設計方法です。 – Holger

+0

「例外的に」は、以前の作品がメッセージに対して行ったすべての操作について忘れてしまった場合、その戻りは無駄になります。しかし、最初のコードセグメントには、実際に前の作業を取り出す方法があることが示されています。私が思ったのは、例外的に例外をスローする関数の引数(この場合は 'List ')を得ることでした。ときには、このチェーンが長くなり、その中の誰かにキャッチしようとするとほとんど無意味になることがあります。 – Tiina

関連する問題