I am trying to call cancel
on CompletableFuture
.
It seems from the docs:
If not already completed, completes this CompletableFuture with a CancellationException. Dependent CompletableFutures that have not already completed will also complete exceptionally, with a CompletionException caused by this CancellationException.
That it should complete them exceptionally which is what I was expecting but instead, it throws and immediate CancellationException.
Here is a sample code
CompletableFuture<?> f = CompletableFuture.supplyAsync(() -> false); f.cancel(true); // Line 7. f.join();
With a repro : https://www.mycompiler.io/view/2v1ME4u
Exception in thread "main" java.util.concurrent.CancellationException at java.base/java.util.concurrent.CompletableFuture.cancel(CompletableFuture.java:2396) at Main.main(Main.java:7)
Line 7 is the f.cancel(true);
line.
Advertisement
Answer
It doesn’t actually throw immediately.
Calling f.cancel(true)
causes a CancellationException
to be created, capturing the stack trace of the call to cancel
. So the stack trace (which is printed because it’s unhandled) contains the line of the f.cancel(true);
call.
But that exception isn’t actually thrown until f.join()
:
Returns the result value when complete, or throws an (unchecked) exception if completed exceptionally
…
Throws:
CancellationException – if the computation was cancelled
You can see this by putting in a few more print statements into your example code:
CompletableFuture<?> f = CompletableFuture.supplyAsync(() -> false); f.cancel(true); // Line 8. try { f.join(); } catch (CancellationException e) { System.out.println("CancellationException was thrown at call to f.join()"); e.printStackTrace(System.out); }
Output:
CancellationException was thrown at call to f.join() java.util.concurrent.CancellationException at java.base/java.util.concurrent.CompletableFuture.cancel(CompletableFuture.java:2396) at Main.main(Main.java:8)