whenComplete documentation says:
Returns a new CompletionStage with the same result or exception as at this stage , which performs the specified action after completion of this stage.
(my accent)
This implies that the exception is not absorbed by this step, since it is assumed that it will have the same result or exception. However, you may be surprised at the fact that in subsequent stages an exception will be received from the previous stage, enclosed in a CompletionException , as described here , so this is not exactly the same exception:
CompletableFuture<String> test=new CompletableFuture<>(); test.whenComplete((result, ex) -> System.out.println("stage 2: "+result+"\t"+ex)) .exceptionally(ex -> { System.out.println("stage 3: "+ex); return ""; }); test.completeExceptionally(new IOException());
will print:
stage 2: null java.io.IOException stage 3: java.util.concurrent.CompletionException: java.io.IOException
Note that you can always add multiple actions in one step instead of a chain:
CompletableFuture<String> test=new CompletableFuture<>(); test.whenComplete((result, ex) -> System.out.println("stage 2a: "+result+"\t"+ex)); test.exceptionally(ex -> { System.out.println("stage 2b: "+ex); return ""; }); test.completeExceptionally(new IOException());
stage 2b: java.io.IOException stage 2a: null java.io.IOException
Of course, since now there is no relationship between 2a and 2b , there is no ordering between them, and in the case of asynchronous actions, they can be performed simultaneously.
Holger
source share