android/guava/src/com/google/common/util/concurrent/FluentFuture.java
@Partially.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) {
    return (FluentFuture<V>) Futures.catchingAsync(this, exceptionType, fallback, executor);
  }
@Partially.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) {
    return (FluentFuture<V>) Futures.catchingAsync(this, exceptionType, fallback, executor);
  }
Returns a {@code Future} whose result is taken from this {@code Future} or, if this {@code
Future} fails with the given {@code exceptionType}, from the result provided by the {@code
fallback}. {@link AsyncFunction#apply} is not invoked until the primary input has failed, so if
the primary input succeeds, it is never invoked. If, during the invocation of {@code fallback},
an exception is thrown, this exception is used as the result of the output {@code Future}.

<p>Usage examples:

<pre>{@code
// 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());
}</pre>

<p>The fallback can also choose to propagate the original exception when desired:

<pre>{@code
// 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());
}</pre>

<p>When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See
the discussion in the {@link #addListener} documentation. All its warnings about heavyweight
listeners are also applicable to heavyweight functions passed to this method. (Specifically,
{@code directExecutor} functions should avoid heavyweight operations inside {@code
AsyncFunction.apply}. Any heavyweight operations should occur in other threads responsible for
completing the returned {@code Future}.)

<p>This method is similar to {@link java.util.concurrent.CompletableFuture#exceptionally}. It
can also serve some of the use cases of {@link java.util.concurrent.CompletableFuture#handle}
and {@link java.util.concurrent.CompletableFuture#handleAsync} when used along with {@link
#transform}.

@param exceptionType the exception type that triggers use of {@code fallback}. The exception
type is matched against the input's exception. "The input's exception" means the cause of
the {@link ExecutionException} thrown by {@code this.get()} or, if {@code get()} throws a
different kind of exception, that exception itself. To avoid hiding bugs and other
unrecoverable errors, callers should prefer more specific types, avoiding {@code
Throwable.class} in particular.
@param fallback the {@link AsyncFunction} 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 the {@link ExecutionException} thrown by {@code input.get()} or, if
{@code get()} throws a different kind of exception, that exception itself.
@param executor the executor that runs {@code fallback} if the input fails