You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免多次嵌套使用CompletableFuture#whenComplete?

CompletableFuture嵌套回调优化方案

原代码因多层嵌套whenComplete导致回调地狱,业务逻辑堆积在回调中,可读性与维护性极差。以下是具体优化方案:

1. 用链式调用替代嵌套回调

使用thenCompose串联依赖型异步操作(先执行resetGambles,再基于结果触发findAllByQuery),彻底消除多层嵌套的回调结构。

2. 拆分业务逻辑到独立方法

将回调内的业务代码(离线用户待领取奖励处理、在线用户奖励发放)提取为单独方法,让异步流程更清晰,也便于后续单元测试与维护。

3. 统一异常处理

避免每个回调重复编写异常判断逻辑,通过handle方法集中处理整个异步链的异常,减少冗余代码。

优化后的代码

public void resetDailyGambles() {
    synchronized (this) {
        gambleRepository.resetGambles()
                .thenCompose(result -> userRepository.findAllByQuery("WHERE last_gamble_reward IS NOT NULL"))
                .handle((users, throwable) -> {
                    if (throwable != null) {
                        handleResetError(throwable);
                        return null;
                    }
                    processOfflineUsers(users);
                    processOnlineUsers();
                    Bukkit.broadcastMessage("§aDaily gambles reset!");
                    return null;
                });
    }
}

// 处理重置操作异常
private void handleResetError(Throwable throwable) {
    Bukkit.broadcastMessage("§cError resetting daily gambles!");
    throwable.printStackTrace();
}

// 处理离线用户的待领取奖励逻辑
private void processOfflineUsers(List<User> users) {
    for (User user : users) {
        Player player = Bukkit.getPlayerExact(user.getName());
        if (player != null && player.isOnline()) {
            continue;
        }

        GambleReward lastReward = user.getLastGambleReward();
        PendingGambleClaim pendingClaim = new PendingGambleClaim(
                UUID.randomUUID(),
                user.getName(),
                lastReward,
                user.getGambleOccasion(),
                true
        );
        pendingGambleRewardRepository.insert(pendingClaim);

        updateUserGambleState(user);
    }
}

// 更新用户赌博状态
private void updateUserGambleState(User user) {
    user.setGambleOccasion(1);
    user.setLastGambleReward(null);
    user.setLastGambleState(LastGambleState.NONE);
    userRepository.update(user);
}

// 处理在线用户的奖励发放与状态重置
private void processOnlineUsers() {
    for (User user : userCache.getAll().values()) {
        Player player = Bukkit.getPlayerExact(user.getName());
        GambleReward gambleReward = user.getLastGambleReward();

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

优化说明

  • 清晰的异步流程:通过thenCompose串联异步操作,流程逻辑一目了然,告别回调地狱。
  • 职责单一:每个方法仅负责一项具体逻辑,代码可读性与可维护性大幅提升。
  • 集中异常处理:handle方法统一处理整个异步链的异常,避免重复编写异常判断代码。
  • 保留同步控制:保留原代码的synchronized(this)以防止并发执行重置操作,同步块仅控制异步流程的触发入口,不阻塞异步任务执行。

内容的提问来源于stack exchange,提问作者Guilherme Kauã

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 10:52:46