在Java 8及以后的版本中,CompletableFuture提供了一种非常灵活的方式来处理异步任务。相比传统的回调和Future接口,CompletableFuture可以链式组合、异常处理、并发并行执行等,代码更简洁易读。下面以一个典型的异步请求数据并进行处理的例子来说明使用方法。
1. 基础使用
CompletableFuture
<String> future = CompletableFuture.supplyAsync(() -> {
// 模拟耗时操作(例如网络请求)
try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
return "Hello, CompletableFuture!";
});
future.thenAccept(result -> System.out.println("得到结果:" + result));
supplyAsync:在默认的ForkJoinPool中执行耗时任务,返回结果供后续处理。thenAccept:在完成后接收结果进行消费。
2. 组合异步任务
假设我们需要先请求用户信息,然后再根据用户ID去查询订单。两者可以串行或并行组合:
CompletableFuture
<User> userFuture = CompletableFuture.supplyAsync(() -> fetchUser());
CompletableFuture<List<Order>> ordersFuture = userFuture.thenCompose(user ->
CompletableFuture.supplyAsync(() -> fetchOrders(user.getId())));
ordersFuture.thenAccept(orders -> System.out.println("订单数量:" + orders.size()));
thenCompose:将前一个任务的结果作为输入,再返回一个新的CompletableFuture,实现任务链。thenApply:如果不需要再返回Future,只做一次转换,可用thenApply。
3. 并行处理
如果你有多个独立任务,可以使用allOf或anyOf实现并行:
CompletableFuture
<Void> all = CompletableFuture.allOf(
CompletableFuture.runAsync(() -> taskA()),
CompletableFuture.runAsync(() -> taskB()),
CompletableFuture.runAsync(() -> taskC())
);
all.thenRun(() -> System.out.println("所有任务完成"));
runAsync:返回void类型的CompletableFuture。allOf:等待所有Future完成。anyOf:等待任意一个Future完成。
4. 异常处理
在链式调用中,一旦出现异常,后续处理将被跳过。可以使用exceptionally或handle来捕获:
CompletableFuture
<String> future = CompletableFuture.supplyAsync(() -> {
if (new Random().nextBoolean()) throw new RuntimeException("偶发错误");
return "成功";
});
future
.exceptionally(ex -> {
System.err.println("异常:" + ex.getMessage());
return "默认值";
})
.thenAccept(result -> System.out.println("最终结果:" + result));
5. 实践案例:异步查询用户与订单
class User { String id; String name; /* getters */ }
class Order { String id; String userId; /* getters */ }
CompletableFuture
<User> fetchUserAsync(String userId) {
return CompletableFuture.supplyAsync(() -> {
// 模拟查询
try { Thread.sleep(200); } catch (InterruptedException ignored) {}
return new User(userId, "Alice");
});
}
CompletableFuture<List<Order>> fetchOrdersAsync(String userId) {
return CompletableFuture.supplyAsync(() -> {
// 模拟查询
try { Thread.sleep(300); } catch (InterruptedException ignored) {}
return List.of(new Order("O1", userId), new Order("O2", userId));
});
}
void demo(String userId) {
fetchUserAsync(userId)
.thenCompose(user -> fetchOrdersAsync(user.getId()))
.thenAccept(orders -> System.out.println("订单数量:" + orders.size()))
.exceptionally(ex -> {
System.err.println("查询失败:" + ex);
return null;
});
}
调用 demo("U123"),即可看到异步流程完成后打印订单数量。
6. 小结
CompletableFuture使异步编程变得像同步代码一样易读易写。- 通过
supplyAsync,runAsync,thenApply,thenCompose,thenAccept,exceptionally等方法,能够实现复杂的任务流。 - 结合
allOf、anyOf可轻松处理并行任务。 - 充分利用异常处理机制,保持代码健壮。
使用好 CompletableFuture,可以显著提升 Java 后台服务的并发性能与代码可维护性。祝你编码愉快!
