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

kri*_*ath 6 scala future exception

我一直习惯于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) 
}
Run Code Online (Sandbox Code Playgroud)

此代码片段将 a 转换DatabaseExceptionBusinessException. 但是,从问题中的评论来看:Scala恢复或recoverWith

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

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

Mar*_*lic 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)
}
Run Code Online (Sandbox Code Playgroud)

哪个输出

Failed to get Entity by ID. Trying by name...
Entity(42,picard)
Run Code Online (Sandbox Code Playgroud)

请注意我们如何尝试首先通过 获取实体id,然后如果失败,我们又尝试通过name