为了账号安全,请及时绑定邮箱和手机立即绑定

可完成的未来 - 完成方法

可完成的未来 - 完成方法

杨魅力 2022-07-14 16:24:28
我有一个代码: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问题:为什么 c1 和 c2 之间的输出存在差异?为什么需要通过调用在 c1 中重复未来类型:新的 CompletableFuture<整数>()
查看完整描述

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。_


查看完整回答
反对 回复 2022-07-14
  • 1 回答
  • 0 关注
  • 136 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号