为什么Java 8 CompletableFuture thenCompose会根据完成顺序生成不同的异常?

Luk*_*kas 7 java future java-8

我遇到过Java 8 CompletableFuture 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));
}
Run Code Online (Sandbox Code Playgroud)

输出是:

After: java.util.concurrent.CompletionException: java.lang.RuntimeException
Before: java.lang.RuntimeException
Run Code Online (Sandbox Code Playgroud)

问题是,为什么异常包含CompletionException在一个案例中但不包含在另一个案例中?

更新:是相关的错误报告.它已被标记并解析为JDK中的错误.

Dim*_*ima 2

看起来像是jdk库中的一个错误。

在“After”情况下,向目标 future.thenCompose添加一个完成节点,其执行稍后由 触发。完成节点的方法在未来查找异常,并调用目标,将所有异常包装到. 请参阅此处如何创建节点,以及此处查看发生包装的位置。ThenCopy.completeExceptionallyrun.internalCompleteCompletionException

现在,在这种Before情况下,代码路径完全不同。因为 future 已经完成,.thenCompose所以不会创建额外的节点,而是立即调用回调,并简单地返回一个(已经完成的第二个 future),然后您可以在其上调用.whenComplete,这同样不会创建新的完成节点,但只是立即调用回调,为其提供第二个 future 的原始异常。

天哪,看看这段代码,我想向我的学生展示很多他们不应该做的事情......