使用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;
}
}
答案 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);
});
表示与普通代码流相同的逻辑。