T - the type of the asynchronous computation resultpublic interface Future<T> extends InterruptHandler
Future is an abstraction to deal with asynchronicity without having to use callbacks directly or blocking threads. The primary usage for Futures on the JVM is to perform IO operations, which are asynchronous by nature.
Although most IO APIs return synchronously, they do that by blocking the current Thread. For instance, the thread issues a request to a remote system and then waits until a response comes back. Considering that the JVM uses native threads, it is wasteful to block them since it leads to potential thread starvation and higher garbage collection pressure. It is hard to scale a JVM system vertically if the IO throughput is bounded by the number of threads.
From the user perspective, a Future can be in three states:
Instead of exposing this state to the user, Future provides combinators to express computations that run once the Future completes. The results of these combinators are Future instances that can be used to perform other transformations, giving the user a powerful tool to express complex chains of asynchronous transformations.
Let’s say that we need to call a remote service to get the username given an id:
Future<User> user = userService.get(userId);
It’s possible to apply the map transformation that produces a Future for the username string:
Future<String> username = user.map(user -> user.username);
Note that we are using a lambda expression (user -> user.username) that takes a user and returns its username.
Let’s say that now we need to call a service to validate the username string. This is the result if we use the map combinator for it:
Future<Future<Boolean>> isValid =
username.map(username -> usernameService.isValid(username));
Given that the lambda expression calls another service and returns a Future, the produced result is a nested future (Future<Future<Boolean>>). One alternative to flatten this nested result is using Future.flatten:
Future<Boolean> isValidFlat = Future.flatten(isValid);
There’s a convenient combinator called flatMap that applies both map and Future.flatten at once:
Future<Boolean> isValid =
username.flatMap(username -> usernameService.isValid(username));
The flatMap combinator is very flexible and comes from the monad abstraction. Although useful, learning monads and category theory is not a requirement to use Futures. Strictly speaking, Future isn’t a monad since it uses eager evaluation and thus breaks referential transparency. Once a Future is created, it is already running. See the “Execution Model” section for more information.
There are many other useful operators to deal with exceptions, collections of futures, and others.
| Modifier and Type | Field and Description |
|---|---|
static Future<Boolean> |
FALSE
A constant
false future. |
static Future<Boolean> |
TRUE
A constant
true future. |
static Future<Void> |
VOID
A constant void future.
|
| Modifier and Type | Method and Description |
|---|---|
static <T> Future<T> |
apply(java.util.function.Supplier<T> s)
Creates a future with the result of the supplier.
|
<U,R> Future<R> |
biFlatMap(Future<U> other,
java.util.function.BiFunction<? super T,? super U,? extends Future<R>> f)
Waits for this and other (running in parallel), maps the result with f, and flattens the result.
|
<U,R> Future<R> |
biMap(Future<U> other,
java.util.function.BiFunction<? super T,? super U,? extends R> f)
Waits for this and other (running in parallel) and then maps the result with f.
|
static <T> Future<List<T>> |
collect(List<? extends Future<T>> list)
Transforms a list of futures into a future of a list.
|
static Future<Void> |
delay(java.time.Duration delay,
ScheduledExecutorService scheduler)
Returns a void future that is satisfied after the specified delay.
|
Future<T> |
delayed(java.time.Duration delay,
ScheduledExecutorService scheduler)
Delays the result of this future.
|
static <T> Future<List<T>> |
emptyList()
Returns a satisfied future with an immutable empty list.
|
static <T> Future<Optional<T>> |
emptyOptional()
Returns a satisfied future with an empty optional.
|
Future<T> |
ensure(Runnable r)
Runs r when this future completes.
|
static <T> Future<T> |
exception(Throwable ex)
Creates a failed future.
|
static <T> Future<T> |
firstCompletedOf(List<Future<T>> list)
Finds the first future that completes.
|
static <T> Future<T> |
flatApply(java.util.function.Supplier<Future<T>> s)
Applies the provided supplier and flattens the result.
|
<R> Future<R> |
flatMap(java.util.function.Function<? super T,? extends Future<R>> f)
Maps the result of this future to another future and flattens the result.
|
static <T> Future<T> |
flatten(Future<Future<T>> fut)
Flattens a nested future.
|
T |
get(java.time.Duration timeout)
Blocks the current thread until this future is satisfied and gets its result.
|
Future<T> |
interruptible()
Creates a future that will be completed with the interrupt exception if an interrupt is received.
|
boolean |
isDefined()
Checks if this future is completed.
|
void |
join(java.time.Duration timeout)
Blocks the current thread until this future is satisfied.
|
static <T> Future<Void> |
join(List<? extends Future<T>> list)
This method is similar to collect, but it discards the result of the futures.
|
<R> Future<R> |
map(java.util.function.Function<? super T,? extends R> f)
Maps the result of this future to another value.
|
static <T> Future<T> |
never()
Returns a future that is never satisfied.
|
Future<T> |
onFailure(java.util.function.Consumer<Throwable> c)
Executes the Consumer if this future completes with an exception.
|
Future<T> |
onSuccess(java.util.function.Consumer<? super T> c)
Executes the Consumer if this future completes successfully.
|
void |
proxyTo(Promise<T> p)
Proxies the result of this future, successful or not, to a Promise.
|
Future<T> |
rescue(java.util.function.Function<Throwable,? extends Future<T>> f)
If this future completes with an exception, applies the provided rescue function and flattens the result.
|
Future<T> |
respond(Responder<? super T> r)
Executes the Responder once this future completes.
|
static <T> Future<Integer> |
selectIndex(List<Future<T>> list)
Selects the index of the first satisfied future.
|
<R> Future<R> |
transform(Transformer<? super T,? extends R> t)
Maps the result of this future using the provided Transformer.
|
<R> Future<R> |
transformWith(Transformer<? super T,? extends Future<R>> t)
Maps the result of this future using a Transformer that returns another future and flattens the result.
|
default <R> Future<R> |
unsafeCast()
Casts the result of this future.
|
static <T> Future<T> |
value(T v)
Creates a successful future.
|
Future<Void> |
voided()
Creates a future that is satisfied with void when this future completes.
|
static <T> Future<Void> |
whileDo(java.util.function.Supplier<Boolean> cond,
java.util.function.Supplier<Future<T>> f)
Executes the supplier function while the condition is valid.
|
default Future<T> |
within(java.time.Duration timeout,
ScheduledExecutorService scheduler)
Creates a future that fails with a TimeoutException if this future isn’t completed within the timeout.
|
Future<T> |
within(java.time.Duration timeout,
ScheduledExecutorService scheduler,
Throwable exception)
Creates a future that fails with a exception if this future isn’t completed within the timeout.
|
apply, apply, raisestatic final Future<Void> VOID
A constant void future. Useful to represent completed side effects.
static <T> Future<T> never()
Returns a future that is never satisfied.
T - the type of the never satisfied future.static <T> Future<T> apply(java.util.function.Supplier<T> s)
Creates a future with the result of the supplier. Note that the supplier is executed by the current thread. Use FuturePool.async to execute the supplier on a separate thread.
T - the type of the value returned by the Supplier.s - a supplier that may throw an exceptionstatic <T> Future<T> flatApply(java.util.function.Supplier<Future<T>> s)
Applies the provided supplier and flattens the result. This method is useful to apply a supplier safely without having to catch possible synchronous exceptions that the supplier may throw.
s - a supplier that may throw an exceptionstatic <T> Future<T> value(T v)
Creates a successful future.
T - the type of the value.v - the value that satisfies the future.static <T> Future<T> exception(Throwable ex)
Creates a failed future.
T - the type of the failed future.ex - the failure.static <T> Future<T> flatten(Future<Future<T>> fut)
Flattens a nested future. The usage of this method indicates a code smell: a map may have been used instead of flatMap. There are genuine scenarios where flatten is required, though.
T - the type of the future resultfut - the nested futurestatic <T> Future<List<T>> emptyList()
Returns a satisfied future with an immutable empty list.
T - the list typestatic <T> Future<Optional<T>> emptyOptional()
Returns a satisfied future with an empty optional.
T - the optional typestatic <T> Future<List<T>> collect(List<? extends Future<T>> list)
Transforms a list of futures into a future of a list.
list - the futures to collect fromstatic <T> Future<Void> join(List<? extends Future<T>> list)
This method is similar to collect, but it discards the result of the futures. It’s useful to wait for a list of pending future side effects.
list - the futures to wait forstatic <T> Future<Integer> selectIndex(List<Future<T>> list)
Selects the index of the first satisfied future.
list - the list of futures to select fromstatic <T> Future<T> firstCompletedOf(List<Future<T>> list)
Finds the first future that completes.
list - futures to select from.static <T> Future<Void> whileDo(java.util.function.Supplier<Boolean> cond, java.util.function.Supplier<Future<T>> f)
Executes the supplier function while the condition is valid.
cond - a supplier that determines if the while should stop or notf - the body of the while that is executed on each asynchronous iterationstatic Future<Void> delay(java.time.Duration delay, ScheduledExecutorService scheduler)
Returns a void future that is satisfied after the specified delay. It’s a shortcut for Future.VOID.delayed(delay, scheduler)
delay - for how long the future must be delayedscheduler - a scheduler for internal tasks<R> Future<R> map(java.util.function.Function<? super T,? extends R> f)
Maps the result of this future to another value.
f - the mapping function.<R> Future<R> flatMap(java.util.function.Function<? super T,? extends Future<R>> f)
Maps the result of this future to another future and flattens the result.
f - the mapping function that returns another future instance.<R> Future<R> transform(Transformer<? super T,? extends R> t)
Maps the result of this future using the provided Transformer. If this future completes successfully, transformer.onValue is called. If this future completes with an exception, transformer.onException is called.
t - a Transformer that applies the transformation.<R> Future<R> transformWith(Transformer<? super T,? extends Future<R>> t)
Maps the result of this future using a Transformer that returns another future and flattens the result. If this future completes successfully, transformer.onValue is called. If this future completes with an exception, transformer.onException is called.
t - a Transformer that applies the transformation.<U,R> Future<R> biMap(Future<U> other, java.util.function.BiFunction<? super T,? super U,? extends R> f)
Waits for this and other (running in parallel) and then maps the result with f.
other - The other future that becomes the second parameter of f.f - the mapping function. The first parameter is the result of this and the second the result of other.<U,R> Future<R> biFlatMap(Future<U> other, java.util.function.BiFunction<? super T,? super U,? extends Future<R>> f)
Waits for this and other (running in parallel), maps the result with f, and flattens the result.
other - The other future that becomes the second parameter of f.f - the mapping function. The first parameter is the result of this and the second the result of other.Future<T> ensure(Runnable r)
Runs r when this future completes.
r - the Runnable to be executed.Future<T> onSuccess(java.util.function.Consumer<? super T> c)
Executes the Consumer if this future completes successfully.
c - the Consumer to be executed.Future<T> onFailure(java.util.function.Consumer<Throwable> c)
Executes the Consumer if this future completes with an exception.
c - the Consumer to be executed.Future<T> respond(Responder<? super T> r)
Executes the Responder once this future completes. If this future completes successfully, responder.onValue is called. If this future completes with an exception, responder.onException is called.
r - the Responder to be executed.Future<T> rescue(java.util.function.Function<Throwable,? extends Future<T>> f)
If this future completes with an exception, applies the provided rescue function and flattens the result.
Note that it’s possible to return a Future.exception from f if the exception can’t be recovered.
f - the function to be executed.Future<T> interruptible()
Creates a future that will be completed with the interrupt exception if an interrupt is received.
boolean isDefined()
Checks if this future is completed.
T get(java.time.Duration timeout) throws CheckedFutureException
Blocks the current thread until this future is satisfied and gets its result. This method normally only useful for tests, avoid it for production code.
timeout - for how long the thread should wait for the resultCheckedFutureException - wrapper exception used when the result is a checked exception. If the exception is unchecked, it’s thrown without this wrapper.void join(java.time.Duration timeout) throws CheckedFutureException
Blocks the current thread until this future is satisfied. This method normally only useful for tests, avoid it for production code.
This method is similar to get but it doesn’t return the future value nor throws if the future completes with an exception.
timeout - for how long the thread should wait for the resultCheckedFutureException - wrapper exception used when the result is a checked exception. If the exception is unchecked, it’s thrown without this wrapper.Future<Void> voided()
Creates a future that is satisfied with void when this future completes.
Future<T> delayed(java.time.Duration delay, ScheduledExecutorService scheduler)
Delays the result of this future. It method doesn’t take in consideration how long this future takes to be completed. It assumes the state of this future after delay, being it completed or not.
delay - for how long the future must be delayedtimeUnit - the time unit for delayscheduler - used to schedule an internal task to be executed after delay.void proxyTo(Promise<T> p)
Proxies the result of this future, successful or not, to a Promise.
p - the Promise to be updated once this future completes.default Future<T> within(java.time.Duration timeout, ScheduledExecutorService scheduler)
Creates a future that fails with a TimeoutException if this future isn’t completed within the timeout.
timeout - how long to wait for the resulttimeUnit - the time unit of timeout.scheduler - used to schedule an internal task after the timeout.Future<T> within(java.time.Duration timeout, ScheduledExecutorService scheduler, Throwable exception)
Creates a future that fails with a exception if this future isn’t completed within the timeout.
timeout - how long to wait for the resulttimeUnit - the time unit of timeout.scheduler - used to schedule an internal task after the timeout.exception - the exception to be thrown when the future times out.default <R> Future<R> unsafeCast()
Casts the result of this future. Avoid this method since it’s unsafe and can produce a future failed with a ClassCastException.
Copyright © 2017. All Rights Reserved.