Scala Future.traverse内recover无法捕获异常问题咨询
问题产生原因
异常没有被recover捕获的核心原因有两点:
- 你的
transform方法在入参为0时,是在调用方的当前线程同步抛出异常,并没有将异常封装为Future.failed的失败状态。这种情况下调用transform(0)时,方法还没返回Future实例就已经崩溃,后续链式调用的.recover根本没有执行机会。 recover的生效范围仅限其绑定的Future实例内部携带的失败状态——也就是Future异步执行过程中抛出、被ExecutionContext捕获封装的异常,完全无法捕获方法同步调用阶段直接抛出的、还没进入Future生命周期的异常。
正确实现方式
两种修复方案可根据实际场景选择:
方案1:修改transform方法,用Future.failed包装异常
不要在方法体中直接抛出异常,而是返回携带失败状态的Future实例,让异常纳入Future的生命周期管理,这样后续的recover就可以正常捕获处理:
private def transform(in: Int): Future[Boolean] = in match { case i if i < 0 => Future.successful(true) case i if i > 0 => Future.successful(false) case i if i == 0 => Future.failed(new IllegalStateException()) }
该方案修改完成后,你原有massTransform的逻辑不需要做任何调整,recover会正常捕获IllegalStateException并返回false。
方案2:不改动transform,调用时包装同步执行逻辑
如果不方便修改transform的现有实现,可以在调用transform时将整个调用过程包入Future的执行逻辑,让ExecutionContext捕获同步抛出的异常、封装为失败的Future实例,后续recover即可正常生效:
import scala.concurrent.Future import scala.concurrent.ExecutionContext def massTransform(ints: List[Int])(implicit ex: ExecutionContext): Future[List[Boolean]] = { Future.traverse(ints) { i => // Scala 2.13+ 版本可直接使用Future.defer,写法更简洁 Future.defer(transform(i)).recover { case _: IllegalStateException => false } // 低版本Scala可使用Future(transform(i)).flatten实现同等效果 } }
内容的提问来源于stack exchange,提问作者Jelly
相关产品推荐
相关产品推荐

