MST
星途 面试题库

面试题:Java中CompletableFuture如何优雅地处理链式异步任务中的异常

假设有一系列通过CompletableFuture.thenApply、thenCompose等方法构建的链式异步任务,在这个链式任务执行过程中,如果其中某一步出现异常,要求能够统一捕获并处理异常,同时不影响其他任务步骤的资源释放等善后操作。请描述实现思路并给出关键代码示例。
37.9万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试
  1. 实现思路
    • 在链式异步任务中,可以使用exceptionally方法来统一捕获异常。exceptionally方法会在链式任务中的任何一步抛出异常时被触发。
    • 对于资源释放等善后操作,可以在每个任务步骤中确保资源在正常完成或异常时都能正确释放,比如使用try - finally块。另外,Java 7引入的AutoCloseable接口结合try - with - resources语句可以更优雅地处理资源释放,确保无论任务是否成功,资源都会被妥善关闭。
  2. 关键代码示例
import java.util.concurrent.CompletableFuture;

public class CompletableFutureExceptionHandling {
    public static void main(String[] args) {
        CompletableFuture.supplyAsync(() -> {
            // 模拟第一步任务,可能抛出异常
            if (Math.random() < 0.5) {
                throw new RuntimeException("模拟异常");
            }
            return "第一步结果";
        })
       .thenApply(result -> {
            // 模拟第二步任务
            System.out.println("第一步结果: " + result);
            return "第二步结果";
        })
       .thenCompose(result -> {
            // 模拟第三步任务
            System.out.println("第二步结果: " + result);
            return CompletableFuture.completedFuture("第三步结果");
        })
       .exceptionally(ex -> {
            // 统一捕获异常
            System.out.println("捕获到异常: " + ex.getMessage());
            return null;
        })
       .thenAccept(result -> {
            // 无论是否有异常,都会执行到这里
            if (result != null) {
                System.out.println("最终结果: " + result);
            }
        });

        // 防止主线程退出
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在上述代码中:

  • supplyAsync开始一个异步任务,该任务有一定概率抛出异常。
  • thenApplythenCompose进行链式操作。
  • exceptionally捕获前面步骤抛出的异常并进行处理。
  • thenAccept用于处理最终结果(包括异常处理后的结果),并且无论是否有异常,都会执行这一步,在这里可以进行一些最后的资源释放或日志记录等操作。同时,在每个任务步骤内部,如果涉及资源操作,应确保使用合适的机制(如try - finallytry - with - resources)来释放资源。