CompletableFuture特别打破了工作链

时间:2017-09-05 07:57:06

标签: java-8

使用CompletableFuture的想法是因为它提供了一个链,而前几个步骤在最后一步使用它之前封装了bean。因为在这些步骤中可能发生任何异常,exceptionally用于处理错误。但是,exceptionally仅接受Throwable参数,到目前为止,我还没有找到一种方法来获取这些封装的bean。

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.

在上面的例子中,注释是工作流程。但是,由于errorHandler既不接受List<Msg>也不传递它,因此链断开。如何从msgSource获得回报?

修改

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

1 个答案:

答案 0 :(得分: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);
});

表示与普通代码流相同的逻辑。