错误处理与异步 HTTP 流水线
使用 exceptionally、handle 和 whenComplete 处理错误,然后构建异步 HTTP 客户端流水线
错误处理与异步 HTTP 流水线 是 CoddyKit 上的免费 Java Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。
为什么异步错误处理很重要
在异步流程中,异常的传播方式与同步代码不同。您必须使用 exceptionally、handle 或 whenComplete 显式处理错误。
exceptionally:从错误中恢复
exceptionally(Function<Throwable, T>) 仅在异步任务以异常完成时调用。它会提供一个备用值,让处理流水线继续运行。
CompletableFuture<String> safe = fetchUser(id)
.thenApply(User::getName)
.exceptionally(ex -> {
log.warn("Fetch failed: " + ex.getMessage());
return "Anonymous";
});
System.out.println(safe.join()); // "Anonymous" if fetch failedhandle:转换成功与失败结果
handle(BiFunction<T, Throwable, U>) 在成功和失败时都会调用。两个参数中有一个将为 null。
fetchUser(id).handle((user, ex) -> {
if (ex != null) return UserDto.empty();
return UserDto.from(user);
}).thenAccept(dto -> sendResponse(dto));whenComplete:任意结果后的副作用
whenComplete(BiConsumer) 在完成后无论结果如何都会调用。它不会改变结果——请将其用于日志记录、指标记录或清理。
fetchUser(id)
.whenComplete((user, ex) -> {
if (ex != null) metrics.increment("user.fetch.error");
else metrics.increment("user.fetch.success");
})
.thenAccept(u -> sendResponse(u));重试失败的异步任务
通过在失败时递归调用该操作来实现重试逻辑,直到达到最大尝试次数。
CompletableFuture<String> withRetry(Supplier<CompletableFuture<String>> task, int retries) {
return task.get().exceptionallyCompose(ex -> {
if (retries > 0) {
System.out.println("Retrying... " + retries);
return withRetry(task, retries - 1);
}
return CompletableFuture.failedFuture(ex);
});
}Java 11 HttpClient:异步 GET
Java 11 的 HttpClient 通过 sendAsync() 提供完全异步的 HTTP 请求,并返回 CompletableFuture<HttpResponse<String>>。
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users/1"))
.build();
CompletableFuture<String> body = client
.sendAsync(req, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body);串联多个 HTTP 调用
请使用 thenCompose 串联有依赖关系的 HTTP 调用:先获取用户,再使用用户的 ID 获取其订单。
client.sendAsync(userReq, HttpResponse.BodyHandlers.ofString())
.thenApply(r -> parseUser(r.body()))
.thenCompose(user -> client.sendAsync(
buildOrdersRequest(user.getId()),
HttpResponse.BodyHandlers.ofString()))
.thenApply(r -> parseOrders(r.body()))
.thenAccept(orders -> System.out.println("Orders: " + orders.size()));使用 allOf 并行执行 HTTP 调用
并行调用多个端点,然后在全部完成后收集所有响应。
List<URI> endpoints = List.of(uri1, uri2, uri3);
List<CompletableFuture<String>> requests = endpoints.stream()
.map(uri -> client.sendAsync(
HttpRequest.newBuilder(uri).build(),
HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body))
.collect(Collectors.toList());
List<String> responses = CompletableFuture
.allOf(requests.toArray(new CompletableFuture[0]))
.thenApply(v -> requests.stream().map(CompletableFuture::join).collect(Collectors.toList()))
.join();HTTP 调用超时
请直接对异步 HTTP 调用应用 orTimeout,这样服务器响应时间过长时就会取消该调用。
CompletableFuture<String> result = client
.sendAsync(req, HttpResponse.BodyHandlers.ofString())
.orTimeout(5, TimeUnit.SECONDS)
.thenApply(HttpResponse::body)
.exceptionally(ex -> "timeout or error");在流水线中验证状态码
请使用 thenApply 检查 HTTP 状态码;如果状态码表示错误,则抛出领域异常,从而保持流水线的错误处理一致。
.thenApply(response -> {
if (response.statusCode() != 200)
throw new HttpResponseException(response.statusCode());
return response.body();
})组合错误恢复与日志记录
在同一条流水线中,用 whenComplete 记录日志,用 exceptionally 进行恢复——两者可以自然组合。
fetchData()
.whenComplete((r, ex) -> { if (ex != null) log.error("Failed", ex); })
.exceptionally(ex -> fallback())
.thenAccept(result -> process(result));快速检查
哪个 CompletableFuture 方法仅在异步任务失败时调用?
回顾
使用 exceptionally 提供备用值,使用 handle 转换成功和失败两种结果,使用 whenComplete 执行副作用。使用 Java 11 HttpClient、thenCompose 和 allOf 构建异步 HTTP 流水线。
常见问题解答
「错误处理与异步 HTTP 流水线」课时是免费的吗?
是的 — 「错误处理与异步 HTTP 流水线」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。
「错误处理与异步 HTTP 流水线」这节课中我会学到什么?
使用 exceptionally、handle 和 whenComplete 处理错误,然后构建异步 HTTP 客户端流水线 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Java Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「错误处理与异步 HTTP 流水线」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Java Academy 课中编写并运行代码吗?
能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。