我有一个代码:
CompletableFuture<Integer> c1 = new CompletableFuture<Integer>()
.thenApply((data) -> data * 2);
c1.thenAccept(System.out::println);
c1.complete(20);
CompletableFuture<Integer> c2 = new CompletableFuture<>();
c2.thenApply(data -> data * 2)
.thenAccept(System.out::println);
c2.complete(20);
输出:
20 40
问题:
新的CompletableFuture << strong>整数>()
答案 0 :(得分:9)
首先要注意的是CompletableFuture
的方法(例如thenApply
,thenAccept
等)返回一个 new CompletableFuture
实例。这形成了一种“链”,其中每个新阶段都依赖于从其创建的阶段(即其父阶段)。当一个阶段正常或异常完成时,结果将推入其所有相关的未完成 * 阶段(同一阶段可以有多个相关阶段)。>
*正如您将在下面看到的那样,即使其父级尚未完成,您也可以完成一个阶段。如果并且父级完成,则 completed 依赖级将不会被调用,因为它已经完成。 answer by Holger简要介绍了另一个问题。
在第一个示例中,您具有以下内容:
CompletableFuture<Integer> c1 = new CompletableFuture<Integer>()
.thenApply((data) -> data * 2);
c1.thenAccept(System.out::println);
c1.complete(20);
这里c1
是thenApply
而非new CompletableFuture<Integer>()
产生的阶段。调用c1.complete(20)
时,您将使用给定值(thenApply
)(通常)完成 20
阶段。对complete
的调用等效于Function
转换前一阶段的结果并返回20
。现在thenApply
完成了,它将值推入thenAccept
,这导致20
被打印到控制台。
在第二个示例中,您具有以下内容:
CompletableFuture<Integer> c2 = new CompletableFuture<>();
c2.thenApply(data -> data * 2)
.thenAccept(System.out::println);
c2.complete(20);
此处c2
是new CompletableFuture<>()
阶段的父级thenApply
产生的阶段。因此,现在当您调用c2.complete(20)
时,您将完成 root 阶段,该阶段会将值推入thenApply
。 Function
然后通过将值乘以2
并将其结果推入thenAccept
来转换值。这样会导致40
被打印到控制台。
在第一个示例中必须重复<Integer>
的原因是因为编译器无法在没有它的情况下推断出第一阶段的类型。 thenApply
的签名是:
<U> CompletableFuture<U> thenApply(Function<? super T, ? extends U>)
T
由此CompletableFuture
的类型(调用该方法的类型)确定。 U
由Function
确定,并且在一定程度上由变量赋值的左侧确定。这意味着当您使用菱形运算符(<>
)时,您实际上在使用以下内容:
CompletableFuture<Integer> c = new CompletableFuture<Object>()
.thenApply(data -> data * 2);
// same as...
CompletableFuture<Integer> c = new CompletableFuture<>()
.thenApply(data -> data * 2);
由于所有编译器都知道data
的类型是Object
,因此乘法无效; Object
不能乘以2
。请注意,如果您仅将Function
从data -> data * 2
更改为data -> 2
,上述内容将是有效的(但显然这两个功能并不等效)。这是因为分配的左侧与thenApply
而不是new CompletableFuture<>()
的结果有关。
当您明确指定<Integer>
时,编译器便知道T
阶段的输入类型(thenApply
)为Integer
,这意味着它知道{{1} }是data
; Integer
可以乘以Integer
。