如何转换 Scala 中失败的未来异常?
How to transform failed future exceptions in Scala?
我一直使用recover
来转换类似于
的失败期货中的异常
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
。但是,根据问题的评论:
... generally speaking the point of "recover" and "recoverWith" is not to simply transform your exceptions from one type to another, but to recover from the failure by performing the task in a different way so that you no longer have a failure.
所以显然我不应该使用 recover
来转换异常。转换 Future
异常/失败 Future
的正确方法是什么?
既然你只是简单地将一个异常转换为另一个异常,我认为使用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
。
我一直使用recover
来转换类似于
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
。但是,根据问题的评论:
... generally speaking the point of "recover" and "recoverWith" is not to simply transform your exceptions from one type to another, but to recover from the failure by performing the task in a different way so that you no longer have a failure.
所以显然我不应该使用 recover
来转换异常。转换 Future
异常/失败 Future
的正确方法是什么?
既然你只是简单地将一个异常转换为另一个异常,我认为使用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
。