如果有2个CompletionStages,我可以将它们与thenCombine
方法结合使用:
CompletionStage<A> aCompletionStage = getA();
CompletionStage<B> bCompletionStage = getB();
CompletionStage<Combined> combinedCompletionStage =
aCompletionStage.thenCombine(bCompletionStage, (aData, bData) -> combine(aData, bData));
如果我有3个或更多CompletionStages,我可以创建一个thenCombine
方法链,但我必须使用临时对象来传递结果。例如,以下是使用Pair
包中的Triple
和org.apache.commons.lang3.tuple
的解决方案:
CompletionStage<A> aCompletionStage = getA();
CompletionStage<B> bCompletionStage = getB();
CompletionStage<C> cCompletionStage = getC();
CompletionStage<D> dCompletionStage = getD();
CompletionStage<Combined> combinedDataCompletionStage =
aCompletionStage.thenCombine(bCompletionStage, (Pair::of))
.thenCombine(cCompletionStage, (ab, c) ->
Triple.of(ab.getLeft(), ab.getRight(), c))
.thenCombine(dCompletionStage, (abc, d) ->
combine(abc.getLeft(), abc.getMiddle(), abc.getRight(), d));
是否有更好的方法来合并多个CompletionStages的结果?
答案 0 :(得分:32)
将多个阶段结合起来的唯一方法就是使用CompletableFuture
,这些阶段可以与越来越多的阶段进行良好的扩展。如果CompletionStage
不是CompletableFuture
,您仍然可以使用.toCompletableFuture()
转换它们:
CompletableFuture<A> aCompletionStage = getA().toCompletableFuture();
CompletableFuture<B> bCompletionStage = getB().toCompletableFuture();
CompletableFuture<C> cCompletionStage = getC().toCompletableFuture();
CompletableFuture<D> dCompletionStage = getD().toCompletableFuture();
CompletionStage<Combined> combinedDataCompletionStage = CompletableFuture.allOf(
aCompletionStage, bCompletionStage, cCompletionStage, dCompletionStage)
.thenApply(ignoredVoid -> combine(
aCompletionStage.join(), bCompletionStage.join(),
cCompletionStage.join(), dCompletionStage.join()) );
这包含了比通过thenCombine
组合两个阶段更多的样板文件,但是当向其添加更多阶段时,样板文件不会增长。
请注意,即使使用原始thenCombine
方法,您也不需要Triple
,Pair
就足够了:
CompletionStage<Combined> combinedDataCompletionStage =
aCompletionStage.thenCombine(bCompletionStage, (Pair::of)).thenCombine(
cCompletionStage.thenCombine(dCompletionStage, Pair::of),
(ab, cd) -> combine(ab.getLeft(), ab.getRight(), cd.getLeft(), cd.getRight()));
如果你想要结合更多阶段,它仍然不能很好地扩展。
中间解决方案(关于复杂性)可能是:
CompletionStage<Combined> combinedDataCompletionStage = aCompletionStage.thenCompose(
a -> bCompletionStage.thenCompose(b -> cCompletionStage.thenCompose(
c -> dCompletionStage.thenApply(d -> combine(a, b, c, d)))));
这在结构上更简单,但是在更多阶段仍然无法很好地扩展。
答案 1 :(得分:2)
Holger's third answer可以缩短一点:
CompletionStage<Combined> combinedDataCompletionStage = aCompletionStage.thenCompose(
a -> bCompletionStage.thenCompose(
b -> cCompletionStage.thenCombine(dCompletionStage,
(c, d) -> combine(a, b, c, d))));
答案 2 :(得分:2)
我认为CompleableFuture.allOf()函数可以为您提供帮助。
例如:(查看完整的课程here)
List<String> urls = [
"https://webhook.site/1647465b-c28f-4ffe-bbfe-5d3ad95ef994",
"https://webhook.site/1647465b-c28f-4ffe-bbfe-5d3ad95ef994?a=1"
]
CompletableFuture<Response>[] futures = new Completablefuture[2]
for (int i = 0; i < urls.size(); i++) {
futures[i] = asyncHttpClient.prepareGet(urls[i]).execute().toCompletableFuture()
}
CompletableFuture.allOf(futures).thenApply { future ->
return futures.collect { it.join() }
}.thenApply({ responses ->
//Do something with results
responses.each { println("Status code: " + it.statusCode) }
})
答案 3 :(得分:2)
CompletableFuture的任何数量都可以组合(减少)
CompletionStage<A> futA = getA();
CompletionStage<B> futB = getB();
CompletionStage<C> futC = getC();
Stream.of(futA, futB, futC)
.reduce((f1, f2) -> f1.thenCombine(f2, (d1, d2) -> combine(d1, d2));
combine 方法的实现将负责合并数据值(A,B和C),如果A,B和C完全不同,则可能会很棘手。
答案 4 :(得分:1)
我认为您应该使用一个中间对象,但不要使用Pair
和Tuple
public R method() {
CompletableFuture<A> aFuture = getAFuture();
CompletableFuture<B> bFuture = getBFuture();
CompletableFuture<C> cFuture = getCFuture();
CompletableFuture<D> dFuture = getDFuture();
return CompletableFuture.completedFuture(new WellNamedResultHolder())
.thenCombineAsync(aFuture, WellNamedResultHolder::withAResult)
.thenCombineAsync(bFuture, WellNamedResultHolder::withBResult)
.thenCombineAsync(cFuture, WellNamedResultHolder::withCResult)
.thenCombineAsync(dFuture, WellNamedResultHolder::withDResult)
.thenApplyAsync(this::combineAllTheResults);
}
private static class WellNamedResultHolder {
private A aResult;
private B bResult;
private C cResult;
private D dResult;
// Getters
public WellNamedResultHolder withAResult(final A aResult) {
this.aResult = aResult;
return this;
}
public WellNamedResultHolder withBResult(final B bResult) {
this.bResult = bResult;
return this;
}
public WellNamedResultHolder withCResult(final C cResult) {
this.cResult = cResult;
return this;
}
public WellNamedResultHolder withDResult(final D dResult) {
this.dResult = dResult;
return this;
}
}
结果持有人的实际形式显然可以更改以满足您自己的需求,从而为您提供更大的灵活性。您还需要负责这些期货的完成情况。尽管样板更多,但是您获得的代码可以更描述所发生的事情(龙目岛可以整理出哪些内容)。
答案 5 :(得分:0)
我遇到了类似的问题,但是有3个以上的completablefutures,因此基于Holger's的答案,我开发了一个小型通用实用程序。
public static <T, R> CompletableFuture<R> allOf(List<CompletableFuture<T>> args, Function<List<T>, R> combiner) {
final Queue<CompletableFuture<T>> queue = new LinkedList<>();
for (CompletableFuture<T> arg : args) {
queue.add(arg);
}
return aggregator(queue, new ArrayList<>(), combiner);
}
private static <T, R> CompletableFuture<R> aggregator(Queue<CompletableFuture<T>> queue, List<T> arg,
Function<List<T>, R> combiner) {
if (queue.size() == 2)
return queue.poll().thenCombine(queue.poll(), (c, d) -> {
arg.add(c);
arg.add(d);
return combiner.apply(arg);
});
return queue.poll().thenCompose(data -> {
arg.add(data);
return aggregator(queue, arg, combiner);
});
}
答案 6 :(得分:0)
您可以创建一个辅助函数...
combine3(
futureA, futureB, futureC,
(a, b, c) -> {
// let's go!
}).toCompletableFuture();
定义:
private static <A, B, C, D> CompletionStage<D> combine3(
CompletionStage<A> aStage,
CompletionStage<B> bStage,
CompletionStage<C> cStage,
TriFunction<A, B, C, D> f
) {
return aStage.thenCompose(
a -> bStage.thenCombine(cStage,
(b, c) -> f.apply(a, b, c)));
}
interface TriFunction<A, B, C, D> {
D apply(A a, B b, C c);
}