首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >包装单个CompleteableFuture<OlderCat>并将其转换为批量操作,结果为CompleteableFuture<Map<Cat.name,OlderCat>>

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

Stack Overflow用户
提问于 2019-06-06 18:27:41
回答 2查看 375关注 0票数 3

我们有一个异步方法:

代码语言:javascript
运行
复制
public CompletableFuture<OlderCat> asyncGetOlderCat(String catName)

给出一张猫的列表:

代码语言:javascript
运行
复制
List<Cat> cats;

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

代码语言:javascript
运行
复制
public CompletableFuture<Map<String, OlderCat>>

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

我们跟踪了this postthis one,并编写了以下代码:

代码语言:javascript
运行
复制
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之间进行匹配。

它能实现吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-06-06 20:12:27

你就快到了。您不需要将exceptionally()放在初始期货上,但应该在allOf()之后使用handle()而不是thenApply(),因为如果将来失败,allOf()也会失败。

在处理期货时,您可以从结果中筛选出失败的期货,并重新构建预期的映射:

代码语言:javascript
运行
复制
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()的调用被保证是非阻塞的,因为thenApply()仅在所有期货完成后才会执行。

票数 1
EN

Stack Overflow用户

发布于 2019-06-06 19:18:09

据我所知,您需要的是包含所有结果的CompletableFuture,下面的代码正是您所需要的

代码语言:javascript
运行
复制
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()
                        ));
            }
    );
}

它在这里做什么-返回future,它在内部创建更多可完成的未来,并在结束时等待。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56475682

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档