CompletableFuture recoverWith equivalent? i.e. exceptionally but return CompletableFuture<U>

Solution 1:

Is this what you are looking for?

askPong("cause error")
        .handle( (pong, ex) -> ex == null 
                ? CompletableFuture.completedFuture(pong) 
                : askPong("Ping")
        ).thenCompose(x -> x);

Also, do not use the ...Async methods unless you intend for the body of the supplied function to be executed asynchronously. So when you do something like

.handleAsync((x, t) -> {
    if (t != null) {
        return askPong("Ping");
    } else {
        return x;
    })

You are asking for the if-then-else to be run in a separate thread. Since askPong returns a CompletableFuture, there's probably no reason to run it asynchronously.

Solution 2:

Jeopardy question of the day: thenApply is to thenCompose as exceptionally is to what?

I know this was initially java-8, but, since java-12, the answer would be exceptionallyCompose:

exceptionallyCompose[Async](Function<Throwable,? extends CompletionStage<T>> fn [, Executor executor])

Returns a new CompletionStage that, when this stage completes exceptionally, is composed using the results of the supplied function applied to this stage's exception.

As the JavaDoc indicates, the default implementation is:

return handle((r, ex) -> (ex == null)
              ? this
              : fn.apply(ex))
    .thenCompose(Function.identity());

That is, using handle() to call the fallback, and thenCompose() to unwrap the resulting nested CompletableFuture<CompletableFuture<T>> – i.e., what you would have done in previous versions of Java (like in Misha’s answer), except you would have to replace this with completedFuture(r).