ssapgosu
ssapgosu

Reputation: 419

java CompletableFuture completion sequence

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?

Upvotes: 1

Views: 768

Answers (1)

Dmitry Khamitov
Dmitry Khamitov

Reputation: 3276

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

Upvotes: 4

Related Questions