Why CompletableFuture is a better choice instead of Future

Rudraksh Singh Bhati
4 min readFeb 22, 2021

Many times during programming we run into a task that can better be done asynchronously(computationally heavy, I/O etc). Java provides classes and interfaces for such tasks(ExecutorService, Future, CompletableFuture etc). Here we are concerned with the latter two.

What is Future?

A Future represents the result of an asynchronous computation. Methods are provided to check if the computation is complete, to wait for its completion, and to retrieve the result of the computation. The result can only be retrieved using the get() method when the computation has completed, blocking if necessary until it is ready. Future was introduced in Java 5. A future object represents a result that will eventually be returned in the future.

Now the question arises if we already have Future for async tasks why CompletableFuture was released in Java 8.

Future lacked some useful features :

  • You cannot perform further action on a Future’s result without blocking the primary application thread.
  • Multiple Future instances cannot be chained together.
  • Multiple Future instances cannot be combined together.
  • There is no Exception Handling.
  • Cannot manually complete Future instance.

CompletableFuture

CompletableFuture implements Future and CompletionStage interfaces. It was introduced in Java 8 to solve the above limitations of Future along with some additional features for asynchronous programming.

Attaching callbacks:

We can attach a callback to the CompletableFuture instance which gets automatically get triggered and executed when the task is complete. That way, we won’t need to wait for the result and can write the logic that needs to be executed after the completion of the Future inside our callback function. We can attach a series of thenApply() callback methods. The result of one thenApply() method is passed to the next in the series

Chained CompletableFuture:

Multiple CompletableFutures can be chained together to get a composite result.

Response

Here the result of the first CompletableFuture instance is fed as an argument for next and the result for that is fed to the last.

Combined CompletableFuture:

Multiple CompletableFuture instances can be combined to get a new CompletionStage that, when this and the other given stages complete normally, is executed with the results as arguments to the supplied function.

thenCompose() method return a CompletableFuture instance as its own result and is used to chain the next dependent future whereas thenCombine() method is used to combine two independent futures when they are both done.

Exception Handling:

Other than handling exceptions using try/catch CompletableFuture API provide different methods to handle exceptions.

If our current stage completes with an exception, by using the exceptionally() method we can get a new CompletionStage which is executed with the current stage’s exception as the argument.

Response

We can also use the handle() method to handle exceptions from our current stage. It 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.

Response

If the above stage completes normally without any exception result is not null otherwise ex is not null.

Manual Completion:

Many times we want to manually complete a process, CompletableFuture API provides the complete() method which can be used to manually complete any future calls. If our stage is not already completed, it sets the value returned by the get() method and related methods to the given value.

Response

The response from the above method is 5 as we have already set this value in the complete() method of the instance.

Conclusion:

As we can see how CompletableFuture is aimed to tackle the limitations of Future. It provides all the methods from Future API along with the above features. CompletableFuture API provides asynchronous methods for most of the above-used methods which can be further used to enhance our code with more parallel processing. Thank you very much for reading!

References:

--

--