Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

finally block equivalent for exception handling in CompletableFuture

I have CompletableFuture which can return result or exception. I want to perform run some common code in case of exception and normal result. Similar to try catch finally block

Current implementation

CompletableFuture<Integer> future= CompletableFuture.supplyAsync(this::findAccountNumber)
                             .thenApply(this::calculateBalance)                      
                             .thenApply(this::notifyBalance)
                             .exceptionally(ex -> {
                                 //My Exception Handling logic 
                                 return 0;
                             });

Where i can put my finally logic ?

like image 405
Niraj Sonawane Avatar asked Jan 26 '19 09:01

Niraj Sonawane


2 Answers

The closest equivalent to finally is whenComplete. Like handle, it accepts a function receiving either, a result value or a throwable, but it doesn’t provide a substitution result value, but rather, the new completion stage will not alter the result, just like finally.

So

static int decode(String s) {
    try {
        return Integer.parseInt(s);
    }
    finally {
        System.out.println("finally action");
    }
}

is equivalent to

static int decode1(String s) {
    return CompletableFuture.completedFuture(s)
        .thenApply(Integer::parseInt)
        .whenComplete((myParsedInt, error) -> System.out.println("finally action"))
        .join();
}

So when using with

for(String s: Arrays.asList("1234", "foo bar")) try {
    System.out.println("decoded: "+decode(s));
} catch(Exception ex) {
    System.out.println("decoding "+s+" failed with "+ex);
}

the first variant prints

finally action
decoded: 1234
finally action
decoding foo bar failed with java.lang.NumberFormatException: For input string: "foo bar"

and the latter prints

finally action
decoded: 1234
finally action
decoding foo bar failed with java.util.concurrent.CompletionException: java.lang.NumberFormatException: For input string: "foo bar"

Common to both is that an exception thrown within the finally action will supersede the original result, shadowing the exception, if the try block/ previous stage completed exceptionally.

like image 176
Holger Avatar answered Oct 16 '22 11:10

Holger


handle() Method provide more flexible approach. it takes a function receiving either correct result or exception:

From java doc

handle(BiFunction<? super T,Throwable,? extends U> fn)

Returns a new CompletionStage that, when this stage completes either normally or exceptionally, is executed with this stage's result and exception as arguments to the supplied function.

CompletableFuture<Integer> thenApply = CompletableFuture.supplyAsync(this::findAccountNumber)
                         .thenApply(this::calculateBalance)                      
                         .thenApply(this::notifyBalance)        
                         .handle((ok, ex) -> {
                            System.out.println("Code That we want to run in finally ");
                            if (ok != null) {
                                    System.out.println("No Exception !!");
                            } else {

                                System.out.println("Got Exception " + ex.getMessage());
                                return -1;
                            }
                            return ok;
                        });
like image 25
Niraj Sonawane Avatar answered Oct 16 '22 09:10

Niraj Sonawane