>,java,java-stream,completable-future,method-reference"/>

首页 > 解决方案 > 包装和转动单个 CompleteableFuture到具有 CompleteableFuture 结果的批量操作>

问题描述

我们有一个异步方法:

public CompletableFuture<OlderCat> asyncGetOlderCat(String catName)

给定一个 Cats 列表:

List<Cat> cats;

我们喜欢创建一个批量操作,这将导致猫名与其异步结果之间的映射:

public CompletableFuture<Map<String, OlderCat>>

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

我们关注了这篇文章这篇文章,我们想出了这段代码:

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& 之间匹配猫名。

可以实现吗?

标签: javajava-streamcompletable-futuremethod-reference

解决方案


你快到了。你不需要exceptionally()在最初的 futures 上加上 an ,但你应该在之后使用handle()而不是,因为如果任何 future 失败, the will 也会失败。thenApply()allOf()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()保证是非阻塞的,因为thenApply()只有在所有期货完成后才会执行。


推荐阅读