Completable Future Improvements in Java9

Reading Time: 3 minutes

In this article, I will be talking about the improvements and enhancements done in the CompletableFuture class and CompletionStage interface as part of Java9 release. There were a lot of improvements done in the class and interface and new methods were added to them, the biggest improvement was to handle timeout asynchronously which was not seen in Java8.

Completable Future improvements at glance (only the common methods)

  1. defaultExecutor method
  2. copy method
  3. completeAsync method
  4. orTimeout method
  5. completeOnTimeout method
  6. New Factory methods

Let’s talk about these methods in detail to better understand them one by one.

1. defaultExecutor() – This method essentially returns the default executor for futures which do not specify an executor.

defaultExecutor() method in action

Executor executor = new CompletableFuture<>().defaultExecutor();
CompletableFuture nameFuture = CompletableFuture.supplyAsync(() -> "Deepak", executor);
// Should be avoided, only for demonstration purpose
System.out.println(nameFuture.join());

view raw
default-executor
hosted with ❤ by GitHub

2. copy() – returns an immutable copy of the existing CompletableFuture instance, since the copy is immutable it would not affect the original instance in any way.

copy() method in action

CompletableFuture nameFuture = CompletableFuture.supplyAsync(() -> "Deepak");
CompletableFuture nameFutureCopy = nameFuture.copy();
CompletableFuture withSurname = nameFuture.thenApply(name -> "Deepak Mehra");
// Should be avoided, only for demonstration purpose
System.out.println(withSurname.join());
// Change in original instance should affect it's copy instance.
System.out.println(nameFutureCopy.join());

view raw
copy
hosted with ❤ by GitHub

3. completeAsync() – Completes this CompletableFuture with the result of the given Supplier function invoked from an asynchronous task using the default executor.

completeAsync() method in action –

CompletableFuture completableFuture = new CompletableFuture();
CompletableFuture nameFuture = completableFuture.completeAsync(() -> "Deepak");
// Should be avoided, only for demonstration purpose
System.out.println(nameFuture.join());

view raw
complete-async
hosted with ❤ by GitHub

The 4th and 5th methods were essentially introduced to support delay and timeouts and still keep everything non-blocking.

4. orTimeout – Prior to orTimeout() what we had, was the get() method where we can define the Time Units and if the future call is not completed in that particular time, it will raise the timeout exception but this method will block the thread and as a result it will not be non-blocking anymore. In order to deal with this, Java9 introduced orTimeout() which will provide us the timeout functionality and keep the calls non-blocking at the same time i.e the thread will not be blocked for that point of time and you can still have the timeout feature for your future calls.

Let’s understand this with the help of an example here. Suppose, you have a service getUsers which will get you a list of users. Now, you want to throw a timeout exception if the userlist is not returned in 1 seconds say, if you do this with the help of get() method you will be blocking the thread. However, with the use of orTimeout() you can throw TimeoutException and still keep everything non-blocking.

orTimeout in action

public class OrTimeoutDemo {
public static void main(String[] args) {
CompletableFuture orTimeout = CompletableFuture.supplyAsync(() -> {
try {
return getUsers();
} catch (Exception ex) {
System.out.println(ex.getMessage());
return null;
}
})
.orTimeout(1, TimeUnit.SECONDS);
// Should be avoided, only for demonstration purpose
System.out.println(orTimeout.join());
}
private static List getUsers() throws Exception {
// If this value will be more than 1000 i.e more than 1 second, timeout will be raised
Thread.sleep(100);
List users = Arrays.asList("Deepak", "Ayush", "Nitesh", "Santosh", "Simran");
return users;
}
}

view raw
or-timeout
hosted with ❤ by GitHub

5. completeOnTimeout – This method is essentially similar to orTimeout(). However, with this method you can also provide a default or static value if the service is taking too long to respond or there is a TimeoutException. This works more like a method which is capable of returning a fallback value when something goes wrong.

completeOnTimeout() in action –

public class CompleteOnTimeoutDemo {
public static void main(String[] args) {
CompletableFuture orTimeout = CompletableFuture.supplyAsync(() -> {
try {
return getUsers();
} catch (Exception ex) {
System.out.println(ex.getMessage());
return null;
}
})
.completeOnTimeout(getUsersFallback(), 1, TimeUnit.SECONDS);
System.out.println(orTimeout.join());
}
private static List getUsers() throws Exception {
// In this case fallback method will be invoked, if this value is lesser than 1000, i.e 1 second, it will invoke the service only.
Thread.sleep(2000);
List users = Arrays.asList("Deepak", "Ayush", "Nitesh", "Santosh", "Simran");
return users;
}
private static List getUsersFallback() {
return Arrays.asList("Fallback List");
}
}

view raw
complete-on-timeout
hosted with ❤ by GitHub

Apart from these methods, some factory methods were also introduced as part of the improvements to CompletableFuture.

New Static Factory Methods
completedFuture() – Returns a new CompletableFuture that is already completed with the given value.
completedStage() – Returns a new CompletionStage that is already completed with the given value and supports only those methods in interface CompletionStage.
failedStage() – Returns a new CompletionStage that is already completed exceptionally with the given exception and supports only those methods in interface CompletionStage

completedFuture() signature – public static CompletableFuture completedFuture(U value)

completedStage() signature – public static CompletionStage completedStage(U value)

failedStage() signature – public static CompletionStage failedStage(Throwable ex)

Static Factory Methods in Action –

CompletableFuture name = CompletableFuture.completedFuture("Deepak");
CompletionStage name With CompletionStage = CompletableFuture.completedStage("Deepak");
CompletableFuture failedFuture = failedFuture(new TimeoutException());
System.out.println(failedFuture.join());

view raw
future-factory
hosted with ❤ by GitHub

That’s pretty much it from the article, full code can be found on the GitHub repository, feel free to fork it and start practicing the examples. If you have any feedback or queries, please do let me know in the comments. Also, if you liked the article, please give me a thumbs up and I will keep writing blogs like this for you in the future as well. Keep reading and Keep coding 🙂


Knoldus-blog-footer-image

Written by 

Deepak is a Software Consultant having experince of more than 5 years . He is very enthusiastic towards his work and is a good team player. He has sound knowledge of different technologies which include Java, C++, C, HTML, CSS, Javascript, C# always keen to learn new technologies.