Reputation: 13
Why does it not work when I save the future to variable before configuration steps?
@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()
is fine, but withVar()
doesn't work:
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`
A similar problem was with RestTemplateBuilder
, when I wanted make otional init one field
Upvotes: 1
Views: 3562
Reputation: 44150
From the JavaDoc for exceptionally
: "Returns a new CompletableFuture...". It does not mutate the CompleteableFuture that it's called upon.
You are creating a new CompleteableFuture with new behaviour and then throwing that away, then join
ing on the original CompleteableFuture which does not have that behaviour.
It's like saying that String::toUpperCase
doesn't work in this example. It does work, but the result is thrown away.
String foo = "bar";
foo.toUpperCase();
assertEquals("BAR", foo);
Upvotes: 2