链接 CompletableFuture 流还是链接 CompletableFuture?

Chaining stream of CompletableFuture or chaining 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, 2, 3, 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();