Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CompletableFuture exceptionally() and handle() swallowing RuntimeException?

I have the following:

cflst.addAll(asList(
            supplyAsync(() -> mytask.getComp("comp"), executor)
                    .thenAccept(comp -> helper.mapStuff(comp))
                    .exceptionally(ex -> {
                        sout("Some Error");  // Never print
                        return null;
                    })
                    .handle((comp, throwable) -> {
                        sout("Error here" + comp); //always prints regarless of exception
                        return null;
                    }),

    ...

    ));

 CompletableFuture.allOf(cflst.toArray(new CompletableFuture[0])).join();

And MyTask.getComp method

 CompX getComp(String id) {
     client.getData(id);
  }

Client.getData()

 SomeX getData(String id) {
    throw new MyCustomRuntimeException("Blew Up");
 }
  

I thought it when the exception is thrown in myComp method, the exceptionally() block gets the exception. But it does not seem to.

Also, regardless of exception, handle() always gets called !?!?!

I want to be able to catch any exception and handle it as needed (Either rethrow or swallow).

Update

When I catch the exception in getComp method and then re-throw it, exceptionally block gets executed. But not sure why it does not gets executed, when exception is thrown one more level down at getData method?

like image 535
Kevin Rave Avatar asked Apr 24 '26 22:04

Kevin Rave


1 Answers

In your example, you are composing CompletableFutures sequentially.

After .exceptionally(), you get a future that yields null instead of throwing an exception. Therefore, the subsequent .handle() will never observe an exception.

If you want .handle() to get the same exception, you must call it on the same future where you call .exception(). For instance, use a variable to store the future you get after .thenAccept() and then compose .exceptionally() and .handle() on it, instead of sequentially.

However, you should choose between .exceptionally() and .handle():

  • .exceptionally() is usually used to return a default value instead of letting an exception through

  • .handle() is usually used to log, transform and/or wrap the exception like a catch block; don't forget to rethrow if you want the exception to go through

For cleanup actions like a finally block, .whenComplete() is more appropriate.

like image 75
acelent Avatar answered Apr 27 '26 15:04

acelent



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!