completablefuture异常时可用exceptionally()提供默认值或handle()统一处理成功与异常;前者仅捕获前序异常并返回同类型兜底数据,后者总执行且需返回目标类型,适合收口处理。

当 CompletableFuture 执行过程中发生异常时,可以通过 exceptionally() 或 handle() 方法提供默认兜底数据,避免整个链路中断或抛出未处理异常。
用 exceptionally() 捕获异常并返回默认值
exceptionally() 是最常用的方式,它只在前序阶段抛出异常时触发,接收 Throwable 参数,返回与原始 CompletableFuture 相同类型的默认值。
示例:
CompletableFuture<string> future = CompletableFuture.supplyAsync(() -> {
if (Math.random() > 0.5) throw new RuntimeException("调用失败");
return "成功结果";
}).exceptionally(throwable -> {
System.err.println("捕获异常:" + throwable.getMessage());
return "兜底数据"; // 类型必须匹配,这里是 String
});
</string>注意:exceptionally() 不会改变原始异常类型,也不会影响后续正常执行的 thenApply 等操作;它仅用于“补救”异常分支。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
用 handle() 统一处理成功与异常两种情况
如果需要对成功结果和异常都做逻辑判断(比如日志记录、统一转换),handle() 更灵活。它接收两个参数:结果(可能为 null)和异常(可能为 null),必须返回目标类型。
示例:
CompletableFuture<integer> result = CompletableFuture.supplyAsync(() -> {
return 100 / 0; // 抛出 ArithmeticException
}).handle((data, ex) -> {
if (ex != null) {
System.out.println("发生异常:" + ex.getClass().getSimpleName());
return -1; // 默认错误码
}
return data * 2; // 正常处理
});
</integer>关键点:handle() 总是执行,无论是否异常;返回值会作为下一个阶段的输入,适合做“收口”处理。
结合 orElse() 风格的兜底(需配合 completeOnTimeout 或手动 fallback)
CompletableFuture 本身不提供类似 Optional.orElse() 的简洁语法,但可通过组合实现类似效果:
- 用
orTimeout()+exceptionally()实现超时兜底 - 用
applyToEither()合并一个“默认 CompletableFutur”(如已知成功的兜底任务) - 更推荐:用
completeAsync()构建带 fallback 的包装方法,提高复用性
注意事项
-
exceptionally()只捕获前一个阶段的异常,不会捕获自身 lambda 中的新异常 - 若想继续传播异常,可在
exceptionally()中重新 throw,但通常不建议 - 多个异步阶段串联时,每个阶段的异常都需单独兜底,或统一用
handle()收口 - 不要在
exceptionally()中执行耗时或阻塞操作,否则影响线程池效率
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










