CompletableFuture中抛CompletionException却出现ExecutionException的原因
CompletableFuture异常包装差异的原因
核心差异来自于你获取Future结果的方法:get()和join()的设计规范完全不同,导致异常包装表现不一致。
关键细节拆解
get()是Future接口定义的方法,严格遵循JDK对Future的契约:无论任务内部抛出何种异常(包括你主动抛出的CompletionException),get()都会将其统一包装成ExecutionException抛出,原始异常会作为ExecutionException的cause存在。join()是CompletableFuture专属方法,为异步链式调用场景优化:它会直接抛出CompletionException(如果任务是通过CompletionException完成异常的),对于checked异常会自动包装为CompletionException,unchecked异常则直接抛出。
对应你的场景示例
假设你的代码结构如下:
public CompletableFuture<Void> myCompletableFuture() { return CompletableFuture.runAsync(() -> { // 子线程主动抛出异常 throw new InvalidParameterException("非法参数"); }).handleAsync((res, ex) -> { if (ex != null) { // 捕获后抛出CompletionException throw new CompletionException(ex); } return res; }); }
用get()获取结果时的表现
try { myCompletableFuture().get(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (ExecutionException e) { // 输出: class java.util.concurrent.ExecutionException System.out.println(e.getClass()); // 输出: class java.util.concurrent.CompletionException System.out.println(e.getCause().getClass()); // 输出: class InvalidParameterException System.out.println(e.getCause().getCause().getClass()); }
这里get()严格遵循Future契约,把你抛出的CompletionException再次包装成了ExecutionException。
用join()获取结果时的表现
try { myCompletableFuture().join(); } catch (CompletionException e) { // 输出: class java.util.concurrent.CompletionException System.out.println(e.getClass()); // 输出: class InvalidParameterException System.out.println(e.getCause().getClass()); }
这时候就符合你的预期:直接拿到CompletionException,其内部包裹着原始的InvalidParameterException。
额外说明
whenCompleteAsync本身不会改变异常的包装逻辑,它只是在任务完成时异步执行回调逻辑,异常的包装差异完全来自于你最终获取结果的方法选择。
内容的提问来源于stack exchange,提问作者Jiwon
相关产品推荐
相关产品推荐

