Luckily, JDK 9 brought two new methods that provide the functionality everyone longed for – which is crucial for ensuring the proper resiliency when working with asynchronous processing.
In this super-short article, I will try to raise the awareness of the new crucial API methods.
Simply put, after calling the above method. The future will throw an ExecutionException if it doesn’t complete within a specified timeout.
A simple example:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(this::computeEndlessly) .orTimeout(1, TimeUnit.SECONDS); future.get(); // java.util.concurrent.ExecutionException after waiting for 1 second
In this option, we can return a default value once the timeout is reached:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(this::computeEndlessly) .completeOnTimeout(42, 1, TimeUnit.SECONDS); Integer result = future.get(); // 42
As simple as that, although I don’t necessarily like the fact that we’re always forced to precompute the default value. If you look at the signature, you will see, that the value isn’t computed lazily:
public CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)
This could’ve been easily achieved, for example, by providing an alternative API method that accepted Supplier<T> instead of plain T – more about the idea can be found here.
The complete example can be found on GitHub.