CompletableFuture
是在Java 8中引入的,作为Future的增强版,它解决了Future许多使用上的限制。CompletableFuture
支持lambda表达式,提供了更强大的异常处理能力,并且能够通过一系列流式方法调用来组合和串联多个异步操作。
创建CompletableFuture
CompletableFuture
可以通过多种方式创建:
- 使用
CompletableFuture.supplyAsync(Supplier<U> supplier)
从一个Supplier
实例异步地创建一个新的CompletableFuture
。 - 通过
CompletableFuture.runAsync(Runnable runnable)
从Runnable
任务异步地执行操作,但不返回结果。 CompletableFuture.completedFuture(result)
来创建一个已经计算出结果的CompletableFuture
。
异常处理
CompletableFuture
提供了几种处理异常的方式:
exceptionally(Function<Throwable, ? extends T> fn)
允许你处理异常并提供一个替代的结果。handle(BiFunction<? super T, Throwable, ? extends U> fn)
让你处理正常的计算结果或异常情况。
组合与转换CompletableFuture
结果转换
thenApply(Function<? super T,? extends U> fn)
可以将前一个异步任务的结果传递给下一个异步任务。thenApplyAsync(Function<? super T,? extends U> fn)
则是在另一个线程中异步执行函数。
结果消费
thenAccept(Consumer<? super T> action)
接收上一个任务的结果作为参数,但不返回新的CompletableFuture
。thenAcceptAsync(Consumer<? super T> action)
异步执行消费操作。
结果组合
thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)
用于将两个CompletableFuture
的结果合并。thenCompose(Function<? super T, ? extends CompletionStage<U>> fn)
允许你对两个CompletableFuture
进行流水线操作,第二个任务依赖于第一个任务的结果。
实践应用示例
假设我们有两个异步查询服务,一个查询用户的详细信息,另一个查询用户的信用评分。我们可以使用thenCombine
来组合这两个查询,只有当两个查询都完成时,才处理最终结果。
CompletableFuture<User> getUserDetails(String userId) {
return CompletableFuture.supplyAsync(() -> {
// 模拟耗时的查询操作
return new User(userId, "John Doe");
});
}
CompletableFuture<Double> getCreditRating(User user) {
return CompletableFuture.supplyAsync(() -> {
// 模拟耗时的信用评分查询
return 8.5;
});
}
public void displayUserCreditRating(String userId) {
getUserDetails(userId)
.thenCombine(getCreditRating(userId), (user, credit) -> {
return "User " + user.getName() + " has a credit rating of " + credit;
})
.thenAccept(System.out::println);
}
在上述示例中,我们首先异步获取用户的详细信息,然后异步获取用户的信用评分,最后组合这两个异步操作的结果,并显示出来。
结语
CompletableFuture
为Java异步编程提供了强大的工具。通过熟练使用它的API,可以使得异步编程变得更加简洁、灵活,从而提高应用程序的性能和响应性。掌握CompletableFuture
,必将为你的Java并发编程技能锦上添花。