Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Supplier Exception handling with CompletableFuture

Consider the following code

public class TestCompletableFuture {

    BiConsumer<Integer, Throwable> biConsumer = (x,y) -> {
        System.out.println(x);
        System.out.println(y);
    };

    public static void main(String args[]) {
        TestCompletableFuture testF = new TestCompletableFuture();
        testF.start();      
    }

    public void start() {
        Supplier<Integer> numberSupplier = new Supplier<Integer>() {
            @Override
            public Integer get() {
                return SupplyNumbers.sendNumbers();                     
            }
        };
        CompletableFuture<Integer> testFuture = CompletableFuture.supplyAsync(numberSupplier).whenComplete(biConsumer);         
    }       
}

class SupplyNumbers {
    public static Integer sendNumbers(){
        return 25; // just for working sake its not  correct.
    }
}

The above thing works fine. However sendNumbers could also throw a checked exception in my case, like:

class SupplyNumbers {
    public static Integer sendNumbers() throws Exception {
        return 25; // just for working sake its not  correct.
    }
}

Now I want to handle this exception as y in my biConsumer. This will help me in handling the result as well as exception (if any) inside a single function (biConsumer).

Any ideas? Can I use CompletableFuture.exceptionally(fn) here or anything else?

like image 398
ayush Avatar asked Mar 10 '15 09:03

ayush


People also ask

Does CompletableFuture throw exception?

Exception Handling of CompletableFuture The call to get() throws an ExecutionException which causes the root Exception.

Is CompletableFuture get blocking?

The CompletableFuture. get() method is blocking. It waits until the Future is completed and returns the result after its completion.

How do you handle exceptions in runAsync?

runAsync(() -> { //process and throw exception }, anInstanceOfTaskExecutor ) . thenRun(() -> {}) . exceptionally(exception -> { // do something, handle exception }) )); In this case, it will execute thenRun .

How do you use ExecutorService with CompletableFuture?

The CompletableFuture API allows to easily chain more calls with thenApply() , thenCompose() etc. It is thus more flexible than the simple Future returned by ExecutorService. submit() ; Using CompletableFuture allows to easily return a future from your child() method using return CompletableFuture.


1 Answers

The factory methods using the standard functional interfaces aren’t helpful when you want to handle checked exceptions. When you insert code catching the exception into the lambda expression, you have the problem that the catch clause needs the CompletableFuture instance to set the exception while the factory method needs the Supplier, chicken-and-egg.

You could use an instance field of a class to allow mutation after creation, but in the end, the resulting code isn’t clean and more complicated that a straight-forward Executor-based solution. The documentation of CompletableFuture says:

  • All async methods without an explicit Executor argument are performed using the ForkJoinPool.commonPool()

So you know the following code will show the standard behavior of CompletableFuture.supplyAsync(Supplier) while handling checked exceptions straight-forward:

CompletableFuture<Integer> f=new CompletableFuture<>();
ForkJoinPool.commonPool().submit(()-> {
  try { f.complete(SupplyNumbers.sendNumbers()); }
  catch(Exception ex) { f.completeExceptionally(ex); }
});

The documentation also says:

… To simplify monitoring, debugging, and tracking, all generated asynchronous tasks are instances of the marker interface CompletableFuture.AsynchronousCompletionTask.

If you want to adhere to this convention to make the solution even more behaving like the original supplyAsync method, change the code to:

CompletableFuture<Integer> f=new CompletableFuture<>();
ForkJoinPool.commonPool().submit(
  (Runnable&CompletableFuture.AsynchronousCompletionTask)()-> {
    try { f.complete(SupplyNumbers.sendNumbers()); }
    catch(Exception ex) { f.completeExceptionally(ex); }
});
like image 110
Holger Avatar answered Sep 17 '22 15:09

Holger