- java.lang.Object
-
- com.google.common.util.concurrent.internal.InternalFutureFailureAccess
-
- com.google.common.util.concurrent.AbstractFuture<V>
-
- com.google.common.util.concurrent.FluentFuture<V>
-
- All Implemented Interfaces:
ListenableFuture<V>
,Future<V>
@DoNotMock("Use FluentFuture.from(Futures.immediate*Future) or SettableFuture") @GwtCompatible(emulated=true) public abstract class FluentFuture<V extends @Nullable Object> extends AbstractFuture<V>
AListenableFuture
that supports fluent chains of operations. For example:ListenableFuture<Boolean> adminIsLoggedIn = FluentFuture.from(usersDatabase.getAdminUser()) .transform(User::getId, directExecutor()) .transform(ActivityService::isLoggedIn, threadPool) .catching(RpcException.class, e -> false, directExecutor());
Alternatives
Frameworks
When chaining together a graph of asynchronous operations, you will often find it easier to use a framework. Frameworks automate the process, often adding features like monitoring, debugging, and cancellation. Examples of frameworks include:
CompletableFuture
/CompletionStage
Users of
CompletableFuture
will likely want to continue usingCompletableFuture
.FluentFuture
is targeted at people who useListenableFuture
, who can't use Java 8, or who want an API more focused thanCompletableFuture
. (If you need to adapt betweenCompletableFuture
andListenableFuture
, consider Future Converter.)Extension
If you want a class likeFluentFuture
but with extra methods, we recommend declaring your own subclass ofListenableFuture
, complete with a method likefrom(com.google.common.util.concurrent.ListenableFuture<V>)
to adapt an existingListenableFuture
, implemented atop aForwardingListenableFuture
that forwards to that future and adds the desired methods.- Since:
- 23.0
-
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Deprecated Methods Modifier and Type Method Description void
addCallback(FutureCallback<? super V> callback, Executor executor)
Registers separate success and failure callbacks to be run when thisFuture
's computation is complete or, if the computation is already complete, immediately.<X extends Throwable>
FluentFuture<V>catching(Class<X> exceptionType, Function<? super X,? extends V> fallback, Executor executor)
Returns aFuture
whose result is taken from thisFuture
or, if thisFuture
fails with the givenexceptionType
, from the result provided by thefallback
.<X extends Throwable>
FluentFuture<V>catchingAsync(Class<X> exceptionType, AsyncFunction<? super X,? extends V> fallback, Executor executor)
Returns aFuture
whose result is taken from thisFuture
or, if thisFuture
fails with the givenexceptionType
, from the result provided by thefallback
.static <V extends @Nullable Object>
FluentFuture<V>from(FluentFuture<V> future)
Deprecated.no need to use thisstatic <V extends @Nullable Object>
FluentFuture<V>from(ListenableFuture<V> future)
Converts the givenListenableFuture
to an equivalentFluentFuture
.<T extends @Nullable Object>
FluentFuture<T>transform(Function<? super V,T> function, Executor executor)
Returns a newFuture
whose result is derived from the result of thisFuture
.<T extends @Nullable Object>
FluentFuture<T>transformAsync(AsyncFunction<? super V,T> function, Executor executor)
Returns a newFuture
whose result is asynchronously derived from the result of thisFuture
.FluentFuture<V>
withTimeout(long timeout, TimeUnit unit, ScheduledExecutorService scheduledExecutor)
Returns a future that delegates to this future but will finish early (via aTimeoutException
wrapped in anExecutionException
) if the specified timeout expires.FluentFuture<V>
withTimeout(Duration timeout, ScheduledExecutorService scheduledExecutor)
Returns a future that delegates to this future but will finish early (via aTimeoutException
wrapped in anExecutionException
) if the specified timeout expires.-
Methods inherited from class com.google.common.util.concurrent.AbstractFuture
addListener, afterDone, cancel, get, get, interruptTask, isCancelled, isDone, pendingToString, set, setException, setFuture, toString, tryInternalFastPathGetFailure, wasInterrupted
-
-
-
-
Method Detail
-
from
public static <V extends @Nullable Object> FluentFuture<V> from(ListenableFuture<V> future)
Converts the givenListenableFuture
to an equivalentFluentFuture
.If the given
ListenableFuture
is already aFluentFuture
, it is returned directly. If not, it is wrapped in aFluentFuture
that delegates all calls to the originalListenableFuture
.
-
from
@Deprecated public static <V extends @Nullable Object> FluentFuture<V> from(FluentFuture<V> future)
Deprecated.no need to use thisSimply returns its argument.- Since:
- 28.0
-
catching
@GwtIncompatible("AVAILABLE but requires exceptionType to be Throwable.class") public final <X extends Throwable> FluentFuture<V> catching(Class<X> exceptionType, Function<? super X,? extends V> fallback, Executor executor)
Returns aFuture
whose result is taken from thisFuture
or, if thisFuture
fails with the givenexceptionType
, from the result provided by thefallback
.Function.apply(F)
is not invoked until the primary input has failed, so if the primary input succeeds, it is never invoked. If, during the invocation offallback
, an exception is thrown, this exception is used as the result of the outputFuture
.Usage example:
// Falling back to a zero counter in case an exception happens when processing the RPC to fetch // counters. ListenableFuture<Integer> faultTolerantFuture = fetchCounters().catching(FetchException.class, x -> 0, directExecutor());
When selecting an executor, note that
directExecutor
is dangerous in some cases. See the discussion in theAbstractFuture.addListener(java.lang.Runnable, java.util.concurrent.Executor)
documentation. All its warnings about heavyweight listeners are also applicable to heavyweight functions passed to this method.This method is similar to
CompletableFuture.exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>)
. It can also serve some of the use cases ofCompletableFuture.handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>)
andCompletableFuture.handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>)
when used along withtransform(com.google.common.base.Function<? super V, T>, java.util.concurrent.Executor)
.- Parameters:
exceptionType
- the exception type that triggers use offallback
. The exception type is matched against the input's exception. "The input's exception" means the cause of theExecutionException
thrown byinput.get()
or, ifget()
throws a different kind of exception, that exception itself. To avoid hiding bugs and other unrecoverable errors, callers should prefer more specific types, avoidingThrowable.class
in particular.fallback
- theFunction
to be called if the input fails with the expected exception type. The function's argument is the input's exception. "The input's exception" means the cause of theExecutionException
thrown bythis.get()
or, ifget()
throws a different kind of exception, that exception itself.executor
- the executor that runsfallback
if the input fails
-
catchingAsync
@GwtIncompatible("AVAILABLE but requires exceptionType to be Throwable.class") public final <X extends Throwable> FluentFuture<V> catchingAsync(Class<X> exceptionType, AsyncFunction<? super X,? extends V> fallback, Executor executor)
Returns aFuture
whose result is taken from thisFuture
or, if thisFuture
fails with the givenexceptionType
, from the result provided by thefallback
.AsyncFunction.apply(I)
is not invoked until the primary input has failed, so if the primary input succeeds, it is never invoked. If, during the invocation offallback
, an exception is thrown, this exception is used as the result of the outputFuture
.Usage examples:
// Falling back to a zero counter in case an exception happens when processing the RPC to fetch // counters. ListenableFuture<Integer> faultTolerantFuture = fetchCounters().catchingAsync( FetchException.class, x -> immediateFuture(0), directExecutor());
The fallback can also choose to propagate the original exception when desired:
// Falling back to a zero counter only in case the exception was a // TimeoutException. ListenableFuture<Integer> faultTolerantFuture = fetchCounters().catchingAsync( FetchException.class, e -> { if (omitDataOnFetchFailure) { return immediateFuture(0); } throw e; }, directExecutor());
When selecting an executor, note that
directExecutor
is dangerous in some cases. See the discussion in theAbstractFuture.addListener(java.lang.Runnable, java.util.concurrent.Executor)
documentation. All its warnings about heavyweight listeners are also applicable to heavyweight functions passed to this method. (Specifically,directExecutor
functions should avoid heavyweight operations insideAsyncFunction.apply
. Any heavyweight operations should occur in other threads responsible for completing the returnedFuture
.)This method is similar to
CompletableFuture.exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>)
. It can also serve some of the use cases ofCompletableFuture.handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>)
andCompletableFuture.handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>)
when used along withtransform(com.google.common.base.Function<? super V, T>, java.util.concurrent.Executor)
.- Parameters:
exceptionType
- the exception type that triggers use offallback
. The exception type is matched against the input's exception. "The input's exception" means the cause of theExecutionException
thrown bythis.get()
or, ifget()
throws a different kind of exception, that exception itself. To avoid hiding bugs and other unrecoverable errors, callers should prefer more specific types, avoidingThrowable.class
in particular.fallback
- theAsyncFunction
to be called if the input fails with the expected exception type. The function's argument is the input's exception. "The input's exception" means the cause of theExecutionException
thrown byinput.get()
or, ifget()
throws a different kind of exception, that exception itself.executor
- the executor that runsfallback
if the input fails
-
withTimeout
@GwtIncompatible public final FluentFuture<V> withTimeout(Duration timeout, ScheduledExecutorService scheduledExecutor)
Returns a future that delegates to this future but will finish early (via aTimeoutException
wrapped in anExecutionException
) if the specified timeout expires. If the timeout expires, not only will the output future finish, but also the input future (this
) will be cancelled and interrupted.- Parameters:
timeout
- when to time out the futurescheduledExecutor
- The executor service to enforce the timeout.- Since:
- NEXT (but since 28.0 in the JRE flavor)
-
withTimeout
@GwtIncompatible public final FluentFuture<V> withTimeout(long timeout, TimeUnit unit, ScheduledExecutorService scheduledExecutor)
Returns a future that delegates to this future but will finish early (via aTimeoutException
wrapped in anExecutionException
) if the specified timeout expires. If the timeout expires, not only will the output future finish, but also the input future (this
) will be cancelled and interrupted.- Parameters:
timeout
- when to time out the futureunit
- the time unit of the time parameterscheduledExecutor
- The executor service to enforce the timeout.
-
transformAsync
public final <T extends @Nullable Object> FluentFuture<T> transformAsync(AsyncFunction<? super V,T> function, Executor executor)
Returns a newFuture
whose result is asynchronously derived from the result of thisFuture
. If the inputFuture
fails, the returnedFuture
fails with the same exception (and the function is not invoked).More precisely, the returned
Future
takes its result from aFuture
produced by applying the givenAsyncFunction
to the result of the originalFuture
. Example usage:FluentFuture<RowKey> rowKeyFuture = FluentFuture.from(indexService.lookUp(query)); ListenableFuture<QueryResult> queryFuture = rowKeyFuture.transformAsync(dataService::readFuture, executor);
When selecting an executor, note that
directExecutor
is dangerous in some cases. See the discussion in theAbstractFuture.addListener(java.lang.Runnable, java.util.concurrent.Executor)
documentation. All its warnings about heavyweight listeners are also applicable to heavyweight functions passed to this method. (Specifically,directExecutor
functions should avoid heavyweight operations insideAsyncFunction.apply
. Any heavyweight operations should occur in other threads responsible for completing the returnedFuture
.)The returned
Future
attempts to keep its cancellation state in sync with that of the input future and that of the future returned by the chain function. That is, if the returnedFuture
is cancelled, it will attempt to cancel the other two, and if either of the other two is cancelled, the returnedFuture
will receive a callback in which it will attempt to cancel itself.This method is similar to
CompletableFuture.thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>)
andCompletableFuture.thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>)
. It can also serve some of the use cases ofCompletableFuture.handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>)
andCompletableFuture.handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>)
when used along withcatching(java.lang.Class<X>, com.google.common.base.Function<? super X, ? extends V>, java.util.concurrent.Executor)
.- Parameters:
function
- A function to transform the result of this future to the result of the output futureexecutor
- Executor to run the function in.- Returns:
- A future that holds result of the function (if the input succeeded) or the original input's failure (if not)
-
transform
public final <T extends @Nullable Object> FluentFuture<T> transform(Function<? super V,T> function, Executor executor)
Returns a newFuture
whose result is derived from the result of thisFuture
. If this inputFuture
fails, the returnedFuture
fails with the same exception (and the function is not invoked). Example usage:ListenableFuture<List<Row>> rowsFuture = queryFuture.transform(QueryResult::getRows, executor);
When selecting an executor, note that
directExecutor
is dangerous in some cases. See the discussion in theAbstractFuture.addListener(java.lang.Runnable, java.util.concurrent.Executor)
documentation. All its warnings about heavyweight listeners are also applicable to heavyweight functions passed to this method.The returned
Future
attempts to keep its cancellation state in sync with that of the input future. That is, if the returnedFuture
is cancelled, it will attempt to cancel the input, and if the input is cancelled, the returnedFuture
will receive a callback in which it will attempt to cancel itself.An example use of this method is to convert a serializable object returned from an RPC into a POJO.
This method is similar to
CompletableFuture.thenApply(java.util.function.Function<? super T, ? extends U>)
andCompletableFuture.thenApplyAsync(java.util.function.Function<? super T, ? extends U>)
. It can also serve some of the use cases ofCompletableFuture.handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>)
andCompletableFuture.handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>)
when used along withcatching(java.lang.Class<X>, com.google.common.base.Function<? super X, ? extends V>, java.util.concurrent.Executor)
.- Parameters:
function
- A Function to transform the results of this future to the results of the returned future.executor
- Executor to run the function in.- Returns:
- A future that holds result of the transformation.
-
addCallback
public final void addCallback(FutureCallback<? super V> callback, Executor executor)
Registers separate success and failure callbacks to be run when thisFuture
's computation is complete or, if the computation is already complete, immediately.The callback is run on
executor
. There is no guaranteed ordering of execution of callbacks, but any callback added through this method is guaranteed to be called once the computation is complete.Example:
future.addCallback( new FutureCallback<QueryResult>() { public void onSuccess(QueryResult result) { storeInCache(result); } public void onFailure(Throwable t) { reportError(t); } }, executor);
When selecting an executor, note that
directExecutor
is dangerous in some cases. See the discussion in theAbstractFuture.addListener(java.lang.Runnable, java.util.concurrent.Executor)
documentation. All its warnings about heavyweight listeners are also applicable to heavyweight callbacks passed to this method.For a more general interface to attach a completion listener, see
AbstractFuture.addListener(java.lang.Runnable, java.util.concurrent.Executor)
.This method is similar to
CompletableFuture.whenComplete(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>)
andCompletableFuture.whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>)
. It also serves the use case ofCompletableFuture.thenAccept(java.util.function.Consumer<? super T>)
andCompletableFuture.thenAcceptAsync(java.util.function.Consumer<? super T>)
.- Parameters:
callback
- The callback to invoke when thisFuture
is completed.executor
- The executor to runcallback
when the future completes.
-
-