1 回答
TA贡献1821条经验 获得超6个赞
首先要注意的是CompletableFuture(例如thenApply,thenAccept等)的方法返回一个新 CompletableFuture实例。这形成了一种“链”,其中每个新阶段都依赖于创建它的阶段——它的父阶段。当一个阶段正常或异常完成时,结果将被推送到其所有相关的、未完成的*阶段(同一阶段可以有多个相关阶段)。
* 正如您将在下面看到的,即使其父级尚未完成,您也可以完成一个阶段。如果父阶段完成,则不会调用已完成的依赖阶段,因为它已经完成。Holger对另一个问题的回答简要介绍了这种情况的后果。
问题 1
在您的第一个示例中,您具有以下内容:
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的值推送到控制台。thenAccept20
在第二个示例中,您具有以下内容:
CompletableFuture<Integer> c2 = new CompletableFuture<>();
c2.thenApply(data -> data * 2)
.thenAccept(System.out::println);
c2.complete(20);
这c2是由 产生的阶段new CompletableFuture<>(),它是阶段的父thenApply级。因此,现在当您调用时,c2.complete(20)您正在完成将值推送到thenApply. 然后Function通过将值乘以并将2结果推送到 来转换值thenAccept。这导致40打印到控制台。
问题2
您必须<Integer>在第一个示例中重复的原因是因为没有它,编译器无法推断第一阶段的类型。的签名thenApply是:
<U> CompletableFuture<U> thenApply(Function<? super T, ? extends U>)
T由 this 的类型决定(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乘法是无效的;aObject不能乘以2。Function请注意,如果您只是将from更改为data -> data * 2to data -> 2(但显然这两个函数不等效),上述内容将是有效的。这是因为赋值的左侧与 的结果有关thenApply,而不是new CompletableFuture<>()。
当您显式指定<Integer>编译器时,就会知道阶段的输入类型 ( T)thenApply是Integer,这意味着它知道data是Integer; Integer 可以乘以2。_
添加回答
举报
