面试题答案
一键面试import java.util.concurrent.CompletableFuture;
public class AsyncTaskChain {
public static void main(String[] args) {
CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> "10");
CompletableFuture<Integer> task2 = task1.thenApplyAsync(s -> {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
return -1;
}
});
CompletableFuture<Integer> task3 = task2.thenApplyAsync(i -> {
if (i != -1) {
return i * i;
}
return -1;
});
task3.thenAccept(System.out::println).join();
}
}
每一步链式调用方法的意义
supplyAsync
:- 用于异步执行一个有返回值的任务。在
task1
中,CompletableFuture.supplyAsync(() -> "10")
创建了一个异步任务,该任务返回字符串"10"
。这里使用supplyAsync
是因为任务有返回值,且希望异步执行以提高效率。
- 用于异步执行一个有返回值的任务。在
thenApplyAsync
:- 在
task2
中,task1.thenApplyAsync(s -> { ... })
接收task1
的返回值(字符串)作为参数s
,并异步地将其转换为整数。这里使用thenApplyAsync
而不是thenApply
是为了在新的线程中执行转换操作,避免阻塞主线程。在这个lambda
表达式中,尝试将字符串解析为整数,如果解析失败,捕获NumberFormatException
并返回默认值-1
。 - 在
task3
中,task2.thenApplyAsync(i -> { ... })
接收task2
的返回值(整数)作为参数i
,并异步地将其平方。同样使用thenApplyAsync
以异步执行平方操作。如果i
不等于-1
(即解析成功),则返回平方值;否则返回-1
。
- 在
thenAccept
:task3.thenAccept(System.out::println)
接收task3
的返回值,并对其进行消费。这里将task3
的返回值打印输出。thenAccept
适用于只需要处理返回值而不需要返回新结果的情况。
异常处理机制
- 解析异常处理:
- 在
task2
的thenApplyAsync
中,通过try - catch
块捕获NumberFormatException
异常,当字符串解析为整数失败时,返回默认值-1
。这样就避免了异常向上传播,保证了后续任务task3
能正常接收一个有效值(即使是默认值)。
- 在
- 平方异常处理:
- 在
task3
的thenApplyAsync
中,通过判断i
是否等于-1
来处理可能在解析阶段产生的异常影响。如果i
为-1
,直接返回-1
,而不进行平方操作,从而避免因异常解析值导致的运行时错误。同时,如果在平方过程中出现其他异常(如Integer
溢出,这里未详细处理,但理论上可以在try - catch
块中捕获处理),也可以类似地进行异常捕获并返回默认值。
- 在
综上所述,通过CompletableFuture
的链式调用和异常处理机制,实现了一系列异步任务的顺序执行,并在遇到异常时返回默认值。