为何thenCombine在BiFunction返回失败CompletionStage时未触发异常完成?与thenCompose的行为差异解析
这事儿的核心在于thenCombine和thenCompose的设计目标完全不同,咱们拆开来说清楚:
先看thenCombine的行为
thenCombine的定位是:等两个独立的CompletableFuture都完成后,用它们的结果执行你传入的BiFunction,然后把这个函数的返回值直接作为新Stage的结果。划重点——它默认期望你的BiFunction返回的是一个普通Java对象,而非另一个CompletionStage。
在你的代码里,BiFunction返回了CompletableFuture.failedStage(new RuntimeException()),但对thenCombine来说,这个失败的Stage只是一个普通对象而已!它不会去“解包”这个Stage的内部状态(成功/失败),而是直接把这个对象当作自己的结果返回。所以整个thenCombine返回的Stage是正常完成的,它的结果就是那个失败的Stage实例,自然whenComplete里的myEx就是null,会打印"No exception"。
你可以把这段代码等价理解成:
// 失败的Stage被当作普通结果返回,整个外层Stage是正常完成的 CompletableFuture<CompletableFuture<Void>> result = CompletableFuture.completedFuture(true) .thenCombine(CompletableFuture.completedFuture(true), (x,y) -> CompletableFuture.failedStage(new RuntimeException()) ); // 调用result.get()会拿到那个失败的Stage,而不是抛出异常
再看thenCompose的行为
thenCompose是专门用来做链式异步操作的,相当于异步版的flatMap。它期望你传入的函数返回一个CompletionStage,然后会完全接管这个Stage的状态:如果函数返回的Stage成功,thenCompose返回的Stage就带着成功结果;如果函数返回的Stage失败,thenCompose返回的Stage也会同步变成失败状态,把异常直接传递下去。
所以在你的第二个例子里,函数返回了一个失败的Stage,thenCompose直接继承了这个失败状态,whenComplete自然就能捕获到异常,打印"There was an exception"。
一句话总结
thenCombine:合并两个异步结果,生成普通值,不处理嵌套的Stage;thenCompose:用前一个异步结果启动下一个异步操作,传递嵌套Stage的成功/失败状态。
内容的提问来源于stack exchange,提问作者Pcgomes

