Search code examples
javacompletable-future

How do I optionally chain another independent CompletableFuture if the first condition doesn't pass?


I have a method like this:

private CompletionStage<Void> example(final Resource resource) {
    return firstMatcher.match(resource)
        .whenComplete((op, t) -> {
            if (t != null || !op.isPresent()) {
                LOGGER.debug("resource doesn't match");
            }
        })
        .thenAccept(optMatch -> optMatch.ifPresent(match -> {
            LOGGER.debug("resource matches");

            // DONE
        }));

    // OR ELSE (Not sure how to chain this piece)

    return secondMatcher.match(resource)
        .whenComplete((op, t) -> {
            if (t != null || !op.isPresent()) {
                LOGGER.debug("resource doesn't match");
            }
        })
        .thenAccept(optMatch -> optMatch.ifPresent(match -> {
            LOGGER.debug("resource matches");

            // DONE
        }));

I would like to return a method that first matches my resource with the firstMatcher. If a match is found, it ends there. But if a match is not found, then it relies on the secondMatcher. Is it possible to chain this into a single method?


Solution

  • You need something like this:

    private CompletionStage<Void> example(final Resource resource) {
            return firstMatcher
                    .match( resource )
                    .thenCompose( firstMatch -> {
                        if ( firstMatch.isPresent() ) {
                            LOGGER.debug( "resource matches first" );
                            return CompletableFuture.completedFuture( null );
                        }
                        LOGGER.debug("resource doesn't match first");
                        return secondMatcher
                                .match( resource )
                                .thenCompose( secondMatch -> {
                                    if ( secondMatch.isPresent() ) {
                                        LOGGER.debug( "resource matches second" );
                                        return CompletableFuture.completedFuture( null );
                                    }
                                    LOGGER.debug("resource doesn't match second");                       
                                    // I'm returning a failed CompletionStage
                                    // but you can add a third matcher or return something else.
                                    // It depends on your requirements
                                    return CompletableFuture.failed(new MatchNotFoundException());
                                });
                    } );
    }
    

    Note that I've removed the whenComplete because they make the example more verbose, but you can add them back if you need to.