如何避免多次嵌套使用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ã
相关产品推荐
相关产品推荐

