包装一个CompleteableFuture <OlderCat>并将其转换为批量操作,结果为CompleteableFuture <Map <Cat.name,OlderCat >>

时间:2019-06-06 10:27:41

标签: java java-stream completable-future method-reference

我们有一个异步方法:

public CompletableFuture<OlderCat> asyncGetOlderCat(String catName)

给出猫的清单:

List<Cat> cats;

我们想创建一个批量操作,该操作将在cat名称与其异步结果之间产生映射:

public CompletableFuture<Map<String, OlderCat>>

我们还喜欢,如果从asyncGetOlderCat抛出异常,则不会将猫添加到地图中。

我们同时关注this postthis 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之间进行匹配。

可以实现吗?

2 个答案:

答案 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()
                        ));
            }
    );
}

它在这里的作用-返回未来,这将在内部创造更多可完成的未来,并在最后等待。