[英]Why Java 8 CompletableFuture thenCompose generates different exception depending on the order of completion?
I have encountered strange behavior of Java 8 CompletableFuture thenCompose method. 我遇到过Java 8 CompletableFuture thenCompose方法的奇怪行为。 I have two tests that differ only in order of execution.
我有两个测试,仅在执行顺序上有所不同。 Both tests simulate failure in the CompletableFuture generated in thenCompose.
两个测试都模拟thenCompose中生成的CompletableFuture中的失败。
@Test
public void completedAfter() {
CompletableFuture<String> future1 = new CompletableFuture<>();
CompletableFuture<String> future2 = new CompletableFuture<>();
future1.thenCompose(x -> future2).whenComplete((r, e) -> System.out.println("After: " + e));
future1.complete("value");
future2.completeExceptionally(new RuntimeException());
}
@Test
public void completedBefore() {
CompletableFuture<String> future1 = new CompletableFuture<>();
CompletableFuture<String> future2 = new CompletableFuture<>();
future1.complete("value");
future2.completeExceptionally(new RuntimeException());
future1.thenCompose(x -> future2).whenComplete((r, e) -> System.out.println("Before: " +e));
}
The output is: 输出是:
After: java.util.concurrent.CompletionException: java.lang.RuntimeException
Before: java.lang.RuntimeException
The question is, why is the exception wrapped in CompletionException
in one case but not in the other? 问题是,为什么在一个案例中包含在
CompletionException
中但在另一个案例中却没有包含异常?
Update: Here is related bug report. 更新: 这是相关的错误报告。 It has been marked and resolved as a bug in JDK.
它已被标记并解析为JDK中的错误。
Seems like a bug in the jdk library. 好像是jdk库中的一个bug。
In the "After" case, .thenCompose
adds a ThenCopy
completion node to the target future, whose execution is later triggered by .completeExceptionally
. 在“After”情况下,
.thenCompose
将一个ThenCopy
完成节点添加到目标future,其执行稍后由.completeExceptionally
触发。 The completion node's run
method finds the exception on the future, and calls .internalComplete
on the destination, that wraps all exceptions into CompletionException
. 完成节点的
run
方法在将来找到异常,并在目标上调用.internalComplete
,它将所有异常包装到CompletionException
。 See here how the node is created, and here for where the wrapping happens. 请参阅此处如何创建节点,以及此处的包装发生位置。
Now, in the Before
case, the code path is completely different. 现在,在
Before
案例中,代码路径完全不同。 Because the future is already completed, .thenCompose
does not create additional nodes, but invokes the callback right away, and simply returns an (already completed second future), on which you then call .whenComplete
, which, again, does not bother to create a new completion node, but simply invokes the callback right away, giving it the original exception from the second future. 因为未来已经完成,
.thenCompose
不会创建额外的节点,而是立即调用回调,然后只返回一个(已经完成的第二个未来),然后调用.whenComplete
,再次,它无需创建一个新的完成节点,但只是立即调用回调 ,从第二个未来给它原始的异常。
Boy, looking at this code, there are so many examples I want to show to my students of what they should never do ... 男孩,看着这段代码,有很多例子我想向学生展示他们应该做的事情......
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.