Search code examples
javaasynchronouscompletable-future

How to prevent multiple CompletableFuture#whenComplete concat?


I have this code, and i feel it is so ugly because i'm using multiples whenComplete

public void resetDailyGambles() {
    synchronized (this) {
        gambleRepository.resetGambles().whenComplete((result, throwable) -> {
            if (throwable != null) {
                Bukkit.broadcastMessage("§cError resetting daily gambles!");
                throwable.printStackTrace();
                return;
            }

            userRepository.findAllByQuery("WHERE last_gamble_reward IS NOT NULL")
                .whenComplete((users, throwable2) -> {
                    if (throwable2 != null)
                        throw new RuntimeException(throwable2);

                    for (User user : users) {
                        GambleReward last = user.getLastGambleReward();
                        Player player = Bukkit.getPlayerExact(user.getName());

                        if (player != null && player.isOnline()) {
                            continue;
                        }

                        PendingGambleClaim pendingGambleClaim = new PendingGambleClaim(UUID.randomUUID(), user.getName(), last, user.getGambleOccasion(), true);
                        pendingGambleRewardRepository.insert(pendingGambleClaim);

                        user.setGambleOccasion(1);
                        user.setLastGambleReward(null);
                        user.setLastGambleState(LastGambleState.NONE);

                        userRepository.update(user);
                    }

                    for (User user : userCache.getAll().values()) {
                        Player player = Bukkit.getPlayerExact(user.getName());

                        GambleReward gambleReward = user.getLastGambleReward();
                        if (gambleReward != null && player != null && player.isOnline()) {
                            user.getLastGambleReward().give(player, user.getGambleOccasion());
                            user.setGambleOccasion(1);
                            user.setLastGambleReward(null);
                            user.getGambles().clear();
                        }
                    }

                    Bukkit.broadcastMessage("§aDaily gambles reset!");
                });
        });
    }
}

Solution

  • You are probably looking for CompletableFuture.thenCompose. That function is analog of Optional.flatMap, is designed to execute chained completable futures and get resulting CompletableFuture. A brief example of usage:

        gambleRepository.resetGambles()
                .thenCompose(resetResult -> userRepository.findAllByQuery("WHERE last_gamble_reward IS NOT NULL")) // assume findAllByQuery returns CompletableFuture
                .whenComplete((users, throwable) -> /* your logic*/); // throwable could relate both to resetGambles and findAllByQuery call