问题
I have always used recover
to transform exceptions in failed futures similar to
def selectFromDatabase(id: Long): Future[Entity] = ???
val entity = selectFromDatabase(id) recover {
case e: DatabaseException =>
logger.error("Failed ...", e)
throw new BusinessException("Failed ...", e)
}
This code snippet transforms a DatabaseException
into a BusinessException
. However, from a comment in the question: Scala recover or recoverWith
... 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.
So apparently I am not supposed to use recover
to transform exceptions. What is the correct way to transform Future
exceptions / failed Future
?
回答1:
Since you are simply transforming an exception to another exception, I think using recover
is ok. Use recoverWith
when you want to try a different strategy for solving the problem, that is, when you hope to get a successful result back. For example consider the following use of 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)
}
which outputs
Failed to get Entity by ID. Trying by name...
Entity(42,picard)
Note how we attempted to first get the entity by id
, and then failing that, we attempted by name
.
来源:https://stackoverflow.com/questions/59099000/how-to-transform-failed-future-exceptions-in-scala