用 CompletableFuture 时,别漏掉异常处理
【摘要】 用 CompletableFuture 时,别漏掉异常处理在 Java 项目里,CompletableFuture 常被用来并行调用多个接口。代码看起来简洁了,但异步任务里的异常不会像普通方法调用那样直接出现在当前线程中,处理不当时,问题可能一直到 join() 才暴露出来。下面这段代码可以并行查询用户和订单:CompletableFuture<User> userFuture = ...
用 CompletableFuture 时,别漏掉异常处理
在 Java 项目里,CompletableFuture 常被用来并行调用多个接口。代码看起来简洁了,但异步任务里的异常不会像普通方法调用那样直接出现在当前线程中,处理不当时,问题可能一直到 join() 才暴露出来。
下面这段代码可以并行查询用户和订单:
CompletableFuture<User> userFuture =
CompletableFuture.supplyAsync(() -> userService.findUser(id));
CompletableFuture<List<Order>> orderFuture =
CompletableFuture.supplyAsync(() -> orderService.findOrders(id));
CompletableFuture.allOf(userFuture, orderFuture).join();
allOf 只负责等待所有任务结束,并不会把各个结果整理出来,也不会吞掉异常。只要其中一个任务失败,调用 join() 时就可能抛出 CompletionException。需要拿到结果时,通常还要分别调用 get() 或 join()。
异常处理可以放在任务链上。比如,查询订单失败时返回空列表:
CompletableFuture<List<Order>> orderFuture =
CompletableFuture.supplyAsync(() -> orderService.findOrders(id))
.exceptionally(ex -> {
log.warn("查询订单失败,用户 id: {}", id, ex);
return Collections.emptyList();
});
如果既要处理成功结果,也要处理失败情况,可以使用 handle。它会接收结果和异常,因此适合统一转换成一个明确的返回值。需要注意,exceptionally 主要用于异常恢复,而 whenComplete 更适合记录日志;后者不会把异常转换成正常结果。
另外,默认的异步任务通常使用公共线程池。若任务会访问数据库或进行网络请求,最好传入专用的 Executor,避免阻塞任务占满公共线程池。异步代码的重点不只是“并行起来”,还要明确异常如何传递、线程由谁管理。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)