Here, our code will wait until findCustomerDetails() works and return the result or the timeout happens. There is no way, to explicitly complete this future.
Let’s assume, we have to design a booking flow for parking. The flow looks like as follow:
Booking Flow
Future does not provide any way for call back after the completion of getCustomerDetails and getParkingDetails, so that we can start booking operation just after.
We would ideally want to do these three operation chained together, and such chaining is not provided by Future APIs.
Similarly, Exception Handling has to be done outside the future APIs.
Completable Future At Work
We would like to approach completable future through examples.
In the example above, the runAsync API of completable future takes runnable, which is provided in lambda. The example above does not show any difference between CompletableFuture as well as Future. But we will get to it.
With this introduction and motivation, it’s time to formally define Completable Future.
Definition
Completable Future implements Future. In a way, Completable Future is a future that can be explicitly completed. It can also act as an CompletionStage by providing way to support dependent functions. It also provides way to callback or in other words, support actions that can be triggered on it’s completion.
Salient Features
When multiple threads wanted to complete, cancel or completeExceptionally , only one of them succeeds
Actions supplied for dependent completions of non-async methods may be performed by the thread used by current completable future or any other caller of completion method
Async methods without having an explicit Executor argument are performed using the ForkJoinPool.commonPool()
In case of exceptional completion with a CompletionException, methods get() and get(long, TimeUnit) throw an ExecutionException
Usage
No Arguement
CompletableFuture<String> completableFuture = new CompletableFuture<>();
String value = completableFuture.get();
The above statement will cause program to run forever. Because there is nothing for the completable future to do.
Let’s say you want to do some action after the completion of a Completable Future. There is nothing to be returned in that action, then you would use thenAccept as shown in the example above. ThenAccept takes input from the previous Completable Future and works on it.
The output of this program is as follow:
Task Running inside completable Future
I am the returned result
Suppose you want to trigger some action after the completion of a completable future. And you don’t have any input from the completable feature as well as no output to be returned.
Output would be:
Task Running inside completable Future
I don't get any input from the previous completableFuture. I am just triggered after it.
ThenCombine allows to trigger a task after both the CompletableFuture is completed. Here, for example, we took 500ms to complete completableFutureFirst and after that, as soon as completableFutureSecond is completed, completableFutureThird is triggered.
Output is:
Task Running inside completable Future
Task Running inside completable Future
Time taken in the Completable Future operation is 563
Result is :: one plus two is three
For whatsoever reason, let’s say we have to complete the future, then we need to use completeAPI. Complete API will complete the future with whatever value we give in the arguement.
Output in this case would be:
Value After Complete: Completing the completable future with this default text
Assume something wrong happened with the task in CompletableFuture and you want to complete it and throw and exception so that the client of your API does appropriate handling of the exception. In such cases, you would use completeExceptionally.
Output for this is as follow:
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.RuntimeException: Task in CompletableFuture Failed
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
at com.company.CompletableFutureAPIUsage.demoCompleteExceptionally(CompletableFutureAPIUsage.java:38)
at com.company.CompletableFutureAPIUsage.main(CompletableFutureAPIUsage.java:20)
Caused by: java.lang.RuntimeException: Task in CompletableFuture Failed
at com.company.CompletableFutureAPIUsage.demoCompleteExceptionally(CompletableFutureAPIUsage.java:36)
… 1 more
You can cancel the future if you don’t need it anymore. Further, there is an option to cancel it if it’s running. CompletableFuture.get() throws an exception when you get in a cancelled completable future. isCancelled() API lets you check if it is cancelled or not.
Output is:
Task Running inside completable Future
Completable Future is cancelled :: true
Exception in thread "main" java.util.concurrent.CancellationException
at java.util.concurrent.CompletableFuture.cancel(CompletableFuture.java:2263)
at com.company.CompletableFutureAPIUsage.demoCancel(CompletableFutureAPIUsage.java:37)
at com.company.CompletableFutureAPIUsage.main(CompletableFutureAPIUsage.java:22)
Leave a Reply