链接 CompletableFuture 流还是链接 CompletableFuture?

问题描述

我看不出这两者之间的主要区别:

List<CompletableFuture<Integer>> intFutures = Stream.of(1,2,3,4)
    .map(input -> CompletableFuture.supplyAsync(() -> computeSomethingLong(input)))
    .map(future -> future.thenApply(input -> input * 2))
    .map(future -> future.thenCompose(computed -> CompletableFuture.supplyAsync(() -> computeSomethingLong(computed))))
    .collect(toList());

还有这个:

List<CompletableFuture<Integer>> intFutures = Stream.of(1,4)
    .map(input -> CompletableFuture.supplyAsync(() -> computeSomethingLong(input))
            .thenApply(computed -> computed * 2)
            .thenCompose(computed -> CompletableFuture.supplyAsync(() -> computeSomethingLong(computed))))
    .collect(toList());

我做了一个测试,结果和执行时间是一样的。 我能看到的唯一区别是第二个提案允许访问沿链的 input 变量。因此,如果我稍后在另一项任务中需要它,我可以使用它。

我错了吗?还有其他区别吗?

解决方法

你的结论是正确的。 (几乎)没有区别——多次调用 map 可能会分配更多的内存,因为需要创建和返回一个新的流实例。在语义上,这两种形式是等价的并产生相同的结果。

如果您需要访问您输入的初始值,那么您需要将这些操作合并为一个操作;否则该变量在操作(即 lambda)范围内不可用。

更一般地说:

stream
    .map(x -> operation1(x))
    .map(x -> operation2(x))
    .map(x -> operation3(x))
    .toList();
// is equivalent to:
stream
   .map(x -> operation3(operation2(operation1(x))))
   .toList();

或者使用方法调用:

stream
    .map(x -> x.method1())
    .map(x -> x.method2())
    .map(x -> x.method3())
    .toList();
// equivalent to:
stream
    .map(x -> x.method1().method2().method3())
    .toList();