completablefuture 的 exceptionally 方法用于在异步任务抛出异常时提供恢复逻辑,它接收一个函数作为参数,该函数以异常对象为输入并返回正常结果。调用此方法后,如果上游阶段成功完成,则直接传递结果;如果发生异常,则执行提供的函数并将返回值作为新阶段的完成值。这种机制允许你在不中断流的情况下优雅地处理错误,例如返回默认值或重试。

exceptionally 与 handle 的区别是什么
exceptionally 仅在出现异常时触发,而 handle 无论成功还是失败都会执行。如果你需要根据是否出错来执行不同的逻辑,或者需要同时访问结果和异常,应使用 handle。若只需在出错时提供备选方案,exceptionally 更简洁且语义明确。

import java.util.concurrent.CompletableFuture;
public class ExceptionallyDemo {
public static void main(String[] args) {
CompletableFuture<string> future = CompletableFuture.supplyAsync(() -> {
throw new RuntimeException("模拟错误");
});
// 使用 exceptionally 提供默认值
CompletableFuture<string> recovered = future.exceptionally(ex -> {
System.out.println("捕获异常: " + ex.getMessage());
return "默认回复";
});
System.out.println("最终结果: " + recovered.join());
}
}</string></string>
如何在链式调用中正确使用 exceptionally
在链式调用中,exceptionally 必须放在可能抛出异常的步骤之后,并且它会终结该分支的错误传播。如果在 exceptionally 之后继续链接其他操作,这些操作将基于恢复后的结果执行,而不是原始异常。确保 exceptionally 返回的类型与上游一致,以便后续步骤能正常处理。

import java.util.concurrent.CompletableFuture;
public class ChainedExceptionallyDemo {
public static void main(String[] args) {
CompletableFuture<integer> future = CompletableFuture.supplyAsync(() -> {
int result = 10 / 0; // 抛出 ArithmeticException
return result;
});
// 链式调用:先计算,再处理异常,最后转换
CompletableFuture<string> finalResult = future
.thenApply(res -> res * 2)
.exceptionally(ex -> {
System.out.println("链式异常处理: " + ex.getClass().getSimpleName());
return 0;
})
.thenApply(res -> "结果值为: " + res);
System.out.println(finalResult.join());
}
}</string></integer>
当 exceptionally 内部再次抛出异常会发生什么
如果在 exceptionally 提供的函数内部再次抛出未捕获的异常,这个新异常将被视为该阶段的完成异常,导致整个 CompletableFuture 进入异常完成状态。这意味着后续的 thenAccept 或 join 调用将抛出 CompletionException。因此,务必在 exceptionally 内部处理所有可能的运行时异常,确保其始终返回有效值。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











