From CompletableFuture javadocs:
Actions supplied for dependent completions of non-async methods may be performed by the thread that completes the current CompletableFuture, or by any other caller of a completion method.
and looking into CompletableFuture.complete()
it calls postComplete()
which seems to pop off the dependent chains and tries to complete them.
To test my understanding, I wrote a simple program
import java.util.concurrent.*;
public class TestCompletableFuture {
public static void main(String[] args) throws Exception {
CompletableFuture<Void> future = new CompletableFuture<Void>()
.whenComplete((res, exc) -> {
System.out.println("inside handle.");
if (exc != null) {
System.out.println("exception.");
}
System.out.println("completed.");
}
);
future.completeExceptionally(new Exception("exception"));
System.out.println("done.");
}
}
the output of the code:
done.
From my understanding, when the main thread calls future.completeExceptionally()
it should invoke the function passed into CompletableFuture.whenComplete()
.
Why is this not the case?
This is because you are completing the wrong future. You need to get a reference to the first stage and complete that to see the whenComplete
in action:
public class TestCompletableFuture {
public static void main(String[] args) throws Exception {
// get reference
CompletableFuture<Void> future = new CompletableFuture<>();
// configure the action that to be run when the future is complete
CompletableFuture<Void> future2 = future
.whenComplete((res, exc) -> {
System.out.println("inside handle.");
if (exc != null) {
System.out.println("exception.");
}
System.out.println("completed.");
}
);
future.completeExceptionally(new Exception("exception"));
System.out.println("done.");
}
}
So, now the code speaks for itself... When the future
is complete run that action (res, exc) -> {...}
. And then just trigger that completion on the future
by calling completeExceptionally(...)
on it.
Another thing to note is that all of the above stages (futures) are completed exceptionally now:
System.out.println(future.isDone()); // true
System.out.println(future2.isDone()); // true
System.out.println(future.isCompletedExceptionally()); // true
System.out.println(future2.isCompletedExceptionally()); // true