如何在Scala中转换失败的Future异常?

6

我一直使用recover来转换失败的future中的异常,就像这样

def selectFromDatabase(id: Long): Future[Entity] = ???

val entity = selectFromDatabase(id) recover {   
  case e: DatabaseException =>
    logger.error("Failed ...", e)
    throw new BusinessException("Failed ...", e) 
}

这段代码片段将一个 DatabaseException 转化为一个 BusinessException。不过,从问题的评论中可以看到:Scala recover or recoverWith

…一般来说,“recover”和“recoverWith”的重点不是简单地将异常类型转换为另一种类型,而是通过以不同的方式执行任务来从故障中恢复,以便不再出现失败。

因此,显然我不应该使用 recover 来转换异常。那么正确的方法是什么,以转换Future 异常/失败的 Future


1
如果您需要将一个失败转换为另一个失败,使用recover(或稍微好一些的是recoverWith {.... Future.failed(new BusinessException)以避免throw)即可。 - Thilo
1个回答

4

由于您只是将一个异常转换为另一个异常,因此我认为使用recover是可以的。当您希望尝试不同的解决问题策略时,请使用recoverWith,也就是当您希望获得成功的结果时。例如,考虑以下recoverWith的用法:

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

object futureRecoverWith extends App {

  case class Entity(id: Int, name: String)

  def selectFromDatabaseById(id: Int): Future[Entity] = Future(throw new RuntimeException("Boom"))
  def selectFromDatabaseByName(name: String): Future[Entity] = Future(Entity(42, "picard"))

  val entity =
    selectFromDatabaseById(42) recoverWith {
      case error =>
        println("Failed to get Entity by ID. Trying by name...")
        selectFromDatabaseByName("picard")
    }

  entity.map(println)
}

输出

Failed to get Entity by ID. Trying by name...
Entity(42,picard)

请注意,我们首先尝试通过 id 获取实体,如果失败,就会尝试通过 name

使用 transform 怎么样?可以避免 抛出 异常,而是返回一个新的 Failed _(缺点是对 Success 进行身份验证)_。 - Luis Miguel Mejía Suárez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接