简体   繁体   中英

Java short circuit CompletableFuture

I am trying to find a way to skip CompletableFuture based on specific conditions.

For example

public CompletableFuture<Void> delete(Long id) {
    CompletableFuture<T> preFetchCf = get(id);
    CompletableFuture<Boolean> cf1 = execute();

    /*This is where I want different execution path, if result of this future is true go further, else do not*/

    // Execute this only if result of cf1 is true
    CompletableFuture<T> deleteCf = _delete(id);
    // Execute this only if result of cf1 is true
    CompletableFuture<T> postDeleteProcess = postDelete(id);
}

What is a good way to achieve this ?

I will prepare a different example than the one you used in the question, because your code is not quite clear in intent from the readers perspective.

First suppose the existing of a CompletableFuture<String> that provides the name of a Star Wars characters.

CompletableFuture<String> character = CompletableFuture.completedFuture("Luke");

Now, imagine I have two other CompletableFuture that represent different paths I may want to follow depending on whether the first completable future provides a character that is a Jedi.

Supplier<CompletableFuture<String>> thunk1 = () -> CompletableFuture.completedFuture("This guy is a Jedi");
Supplier<CompletableFuture<String>> thunk2 = () -> CompletableFuture.completedFuture("This guy is not a Jedi");

Notice that I wrapped the CompletableFuture in aa Supplier , to avoid that they get eagerly evaluated (this is concept known as thunk ).

Now, I go and to my asynchronous chain:

character.thenApply(c -> isJedi(c))
            .thenCompose(isJedi -> isJedi ? thunk1.get() : thunk2.get())
            .whenComplete((answer, error) -> System.out.println(answer));

The use of thenCompose let me choose a path based on the boolean result. There I evaluate one of the thunks and cause it to create a new CompletableFuture for the path I care about.

This will print to the screen "This guys is a Jedi" .

So, I believe what you're looking for is the thenCompose method.

Not sure if I understand your objective, but why won't you just go with future chaining like you said in the comment? Something like this, just to illustrate:

public class AppTest {
    @Test
    public void testCompletableFutures() {
        Integer id = (int) Math.random() * 1000;

        CompletableFuture<Void> testing = AppTest.execute()
                .thenAcceptAsync(result -> {
                    System.out.println("Result is: " + result);
                    if(result)
                        AppTest.delete(id);
                    else
                        throw new RuntimeException("Execution failed");
                })
                .thenApplyAsync(result -> AppTest.postDelete())
                .thenAcceptAsync(postDeleteResult -> {
                    if(postDeleteResult)
                        System.out.println("Post delete cleanup success");
                    else
                        throw new RuntimeException("Post delete failed");
                });
    }

    private static boolean postDelete() {
        System.out.println("Post delete cleanup");
        return Math.random() > 0.3;
    }

    private static CompletableFuture<Boolean> delete(int i) {
        System.out.println("Deleting id = " + i);
        return CompletableFuture.completedFuture(true);
    }

    private static CompletableFuture<Boolean> execute() {
        return CompletableFuture.supplyAsync(() -> Math.random() > 0.5);
    }
}

Of course that doesn't make much real-life sense, but I think it works to show a concept.

If you want to skip the second call after execute based on the result it's clearly not possible since you need that result. The point is that it should not matter for you whether you skipped that or not since it's asynchronous, you are not blocking to wait for that result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM