我们有一个异步方法:
public CompletableFuture<OlderCat> asyncGetOlderCat(String catName)
给出猫的清单:
List<Cat> cats;
我们想创建一个批量操作,该操作将在cat名称与其异步结果之间产生映射:
public CompletableFuture<Map<String, OlderCat>>
我们还喜欢,如果从asyncGetOlderCat
抛出异常,则不会将猫添加到地图中。
我们同时关注this post和this one,我们想到了以下代码:
List<Cat> cats = ...
Map<String, CompletableFuture<OlderCat>> completableFutures = cats
.stream()
.collect(Collectors.toMap(Cat::getName,
c -> asynceGetOlderCat(c.getName())
.exceptionally( ex -> /* null?? */ ))
));
CompletableFuture<Void> allFutures = CompletableFuture
.allOf(completableFutures.values().toArray(new CompletableFuture[completableFutures.size()]));
return allFutures.thenApply(future -> completableFutures.keySet().stream()
.map(CompletableFuture::join) ???
.collect(Collectors.toMap(????)));
但是目前尚不清楚我们如何在allFutures
中访问猫的名称以及如何在OlderCat
和catName之间进行匹配。
可以实现吗?
答案 0 :(得分:1)
您快到了。您无需在初始期货上放置exceptionally()
,但应在handle()
之后使用thenApply()
而不是allOf()
,因为如果任何期货失败,{ {1}}也将失败。
在处理期货时,您可以从结果中筛选出失败的期货,然后重建预期的地图:
allOf()
请注意,由于Map<String, CompletableFuture<OlderCat>> completableFutures = cats
.stream()
.collect(toMap(Cat::getName, c -> asyncGetOlderCat(c.getName())));
CompletableFuture<Void> allFutures = CompletableFuture
.allOf(completableFutures.values().toArray(new CompletableFuture[0]));
return allFutures.handle((dummy, ex) ->
completableFutures.entrySet().stream()
.filter(entry -> !entry.getValue().isCompletedExceptionally())
.collect(toMap(Map.Entry::getKey, e -> e.getValue().join())));
仅在所有将来完成后才会执行,因此保证对join()
的调用是无阻塞的。
答案 1 :(得分:0)
据我所知,您需要的是CompletableFuture
及其所有结果,下面的代码完全可以满足您的需求
public CompletableFuture<Map<String, OlderCat>> getOlderCats(List<Cat> cats) {
return CompletableFuture.supplyAsync(
() -> {
Map<String, CompletableFuture<OlderCat>> completableFutures = cats
.stream()
.collect(Collectors.toMap(Cat::getName,
c -> asyncGetOlderCat(c.getName())
.exceptionally(ex -> {
ex.printStackTrace();
// if exception happens - return null
// if you don't want null - save failed ones to separate list and process them separately
return null;
}))
);
return completableFutures
.entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue().join()
));
}
);
}
它在这里的作用-返回未来,这将在内部创造更多可完成的未来,并在最后等待。