Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functional Java - Interaction between whenComplete and exceptionally

Tags:

In this code:

doSomethingThatMightThrowAnException()   .whenComplete((result, ex) -> doSomethingElse()})   .exceptionally(ex -> handleException(ex)); 

When there is an exception from doSomethingThatMightThrowAnException, are both doSomethingElse and handleException run, or is the exception consumed by either the whenComplete or the exceptionally?

EDIT:

doSomethingThatMightThrowAnException returns a CompletableFuture, which might completeExceptionally. This is the exception I'm talking about.

like image 431
peco Avatar asked Jul 10 '15 10:07

peco


2 Answers

The documentation of whenComplete says:

Returns a new CompletionStage with the same result or exception as this stage, that executes the given action when this stage completes.

(emphasis mine)

This implies that an exception is not swallowed by this stage as it is supposed to have the same result or exception. However, you might be surprised by the fact that subsequent stages will receive the exception of a previous stage wrapped within a CompletionException, as discussed here, so it’s 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 append multiple actions on one stage instead of chaining then:

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 dependency between the stage 2a and 2b, there is no ordering between them and in the case of async action, they may run concurrently.

like image 109
Holger Avatar answered Dec 27 '22 10:12

Holger


The exceptionally method states:

Returns a new CompletableFuture that is completed when this CompletableFuture completes, with the result of the given function of the exception triggering this CompletableFuture's completion when it completes exceptionally; otherwise, if this CompletableFuture completes normally, then the returned CompletableFuture also completes normally with the same value. Note: More flexible versions of this functionality are available using methods whenComplete and handle.

This is not, IMHO written in the clearest english but I would say that means that if an exception is thrown then only the exceptionally action will be triggered. If no exception is thrown then only the normal action will be performed.

like image 23
OldCurmudgeon Avatar answered Dec 27 '22 08:12

OldCurmudgeon