CompletableFuture 如果保存到变量则不起作用

CompletableFuture doesn't work if it saved to variable

为什么在配置步骤之前将未来保存到变量时它不起作用?

@Test
void simple() {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(this::throwException)
            .exceptionally(throwable -> HANDLED);
    assertEquals(HANDLED, future.join());
}

@Test
void withVar() {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(this::throwException);
    future.exceptionally(throwable -> HANDLED);
    assertEquals(HANDLED, future.join());
}

private String throwException() {
    if (true) {
        throw new RuntimeException(FAIL);
    }
    return SUCCESS;
}

simple()可以,但是withVar()不行:

java.util.concurrent.CompletionException: java.lang.RuntimeException: FAIL

at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:314)
at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:319)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1702)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1692)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)`
Caused by: java.lang.RuntimeException: FAIL
    at ru.dionisis.resttest.ComplitableFutureTest.throwException(ComplitableFutureTest.java:35)
    at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
    ... 6 more`

类似的问题出现在 RestTemplateBuilder,当我想在一个字段中创建一个可选的初始值时

来自 the JavaDoc for exceptionally:“Returns 一个 new CompletableFuture...”。它不会改变它所调用的 CompleteableFuture。

您正在创建一个具有新行为的新 CompleteableFuture,然后将其丢弃,然后 join 在没有该行为的原始 CompleteableFuture 上。

这就像说 String::toUpperCase 在这个例子中不起作用。它确实有效,但结果被丢弃了。

String foo = "bar";
foo.toUpperCase();
assertEquals("BAR", foo);