面试题答案
一键面试设计思路
- 任务依赖构建:使用
CompletableFuture
的方法来构建任务之间的依赖关系。例如,thenCompose
用于顺序依赖,thenCombine
用于并行任务完成后的合并。 - 异常处理:通过
exceptionally
方法来捕获任务执行过程中的异常,并返回一个默认值或者进行异常处理。在捕获异常后,我们可以将异常信息封装在返回值中,以便后续任务能够知晓异常情况。 - 返回值传递:确保正常任务的返回值能够正确传递到后续依赖任务中。通过
thenApply
等方法对任务结果进行处理,并传递给下一个任务。
代码实现
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureDependencyExample {
public static void main(String[] args) {
CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() -> {
// 模拟任务A执行
System.out.println("Task A is running");
return "Result of Task A";
});
CompletableFuture<String> taskB = taskA.thenApplyAsync(resultA -> {
// 模拟任务B执行,依赖任务A的结果
System.out.println("Task B is running with result from A: " + resultA);
// 这里可以抛出异常模拟任务失败
if (Math.random() < 0.5) {
throw new RuntimeException("Task B failed");
}
return "Result of Task B";
});
CompletableFuture<String> taskC = taskA.thenApplyAsync(resultA -> {
// 模拟任务C执行,依赖任务A的结果
System.out.println("Task C is running with result from A: " + resultA);
// 这里可以抛出异常模拟任务失败
if (Math.random() < 0.5) {
throw new RuntimeException("Task C failed");
}
return "Result of Task C";
});
CompletableFuture<String> taskD = CompletableFuture.allOf(taskB, taskC)
.thenApplyAsync(v -> {
try {
// 获取任务B和任务C的结果
String resultB = taskB.get();
String resultC = taskC.get();
System.out.println("Task D is running with results from B and C: " + resultB + ", " + resultC);
return "Result of Task D";
} catch (InterruptedException | ExecutionException e) {
// 捕获任务B或任务C执行过程中的异常
throw new RuntimeException("Task B or C failed", e);
}
});
taskD.exceptionally(ex -> {
// 统一捕获任务D执行过程中的异常,包括任务B和任务C传递过来的异常
System.out.println("An exception occurred: " + ex.getMessage());
return "Default result due to exception";
}).thenAccept(System.out::println);
}
}
在上述代码中:
- 任务A:是一个独立的任务,通过
supplyAsync
异步执行并返回结果。 - 任务B和任务C:依赖任务A的结果,通过
thenApplyAsync
异步执行,并可以在执行过程中抛出异常。 - 任务D:依赖任务B和任务C的完成,通过
allOf
方法等待任务B和任务C都完成后执行。在任务D中,通过get
方法获取任务B和任务C的结果,并处理可能的异常。 - 异常处理:通过
exceptionally
方法统一捕获任务执行过程中的异常,并返回默认结果。这样可以确保即使某个任务出现异常,整个流程依然可以继续执行并得到处理结果。