java - 调用 completeExceptionally 时未在 CompletableFuture 上执行最后一次转换
问题描述
我有以下代码:
public final class Start {
private static final CountDownLatch FINAL_THREAD = new CountDownLatch(1);
private static String getValue() {
System.out.println("Waiting...");
try {
Thread.sleep(Duration.ofSeconds(1).toMillis());
return "value";
} catch (InterruptedException e) {
return "interrupted";
}
}
private static void whenComplete(String value, Throwable ex) {
if (ex != null) {
System.out.println("whenComplete Ex: " + ex);
} else {
System.out.println("whenComplete Value: " + value);
}
}
private static String handle(String value, Throwable ex) {
if (ex != null) {
System.out.println("handle Ex: " + ex);
} else {
System.out.println("handle Value: " + value);
}
FINAL_THREAD.countDown();
return value;
}
private static String peek(String value) {
System.out.println("peek: " + value);
return value;
}
private static CompletableFuture<String> createRequest() {
System.out.println("Create....");
return CompletableFuture.supplyAsync(Start::getValue)
.thenApply(Start::peek)
.handle(Start::handle)
.whenComplete(Start::whenComplete);
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
createRequest().completeExceptionally(new RuntimeException("TEST"));
FINAL_THREAD.await();
}
}
当我执行它时,我得到如下输出:
> Task :Start.main()
Create....
Waiting...
peek: value
handle Value: value
BUILD SUCCESSFUL in 10s
我不明白为什么Start::whenComplete
两者都没有被Start::peek
调用Start::handle
。如果我用 whenComplete 切换句柄,则Start::handle
不会被调用,但Start::whenComplete
会。我希望在这种情况下Start::whenComplete
会调用 with RuntimeExeception
,而其他阶段将使用Start::getValue
.
解决方案
我认为文档CompletableFuture
涵盖了这一点,但让我们慢慢了解它,因为它不是那么微不足道。首先,我们需要稍微重构您的代码:
private static CompletableFuture<String> createRequest() {
System.out.println("Create....");
CompletableFuture<String> one = CompletableFuture.supplyAsync(Start::getValue);
CompletableFuture<String> two = one.thenApply(Start::peek);
CompletableFuture<String> three = two.handle(Start::handle);
CompletableFuture<String> four = three.whenComplete(Start::whenComplete);
return four;
}
让我们稍微改变一下你的main
:
public static void main(String[] args) {
CompletableFuture<String> f = createRequest();
boolean didI = f.completeExceptionally(new RuntimeException("TEST"));
System.out.println("have I completed it? : " + didI);
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
}
现在让我们仔细看一下:
CompletableFuture<String> four = three.whenComplete(Start::whenComplete);
通过以下文档whenComplete
:
返回一个与此阶段具有相同结果或异常的新 CompletionStage,它在此阶段完成时执行给定的操作。
把它分成小块:
返回一个新的 CompletionStage (
four
),其结果或异常与此阶段 ( ) 相同,在此阶段 ( ) 完成时three
执行给定的操作 ( )。Start::whenComplete
three
谁应该执行Start::whenComplete
?根据文档:four
。它应该什么时候执行?什么时候three
完成。
根据您的流程,在 three
完成之前,您completeExceptionally
的four
. 所以什么时候three
完成,所以是four
- 意味着它不能执行那个Start::whenComplete
(action
);只是因为它已经完成了。另一种思考方式是,当您的代码到达这一行时:
CompletableFuture<String> four = three.whenComplete(Start::whenComplete);
four
是一个未完成的未来。可以通过两种方式完成:
无论何时
three
完成,从而触发Start::whenComplete
外部(你做什么
completeExceptionally
)
因为您在完成之前在 three
外部完成了它,所以它不会运行该操作。
如果你将一个动作链接到你完成的未来:
four.whenComplete(Start::whenComplete);
这是您将看到所需输出的时候。
推荐阅读
- javascript - 本机 Web 组件之间的消息传递 v1
- javascript - 如何使用 Jquery 从下一个父 li 元素中添加和删除类
- c++ - 选中/取消选中时如何更改 QToolBar 上的 QAction 图标?
- python - 根据总和对数组列进行排序
- amazon-web-services - 为基于订阅的视频流创建移动应用程序的成本效益高的方法是什么?
- jenkins - 从詹金斯下游作业发送构建状态
- python - 如何在构建我的 python 项目时包含 nltk 数据?
- java - 在 dropwizard 应用程序中集成 Audit4J
- android - 主动跟踪任务示例在 Mavic Air 中不起作用
- amazon-web-services - Cognito - 导入用户后未发送电子邮件