Map the Exception of a failed Future

25,132

Solution 1

There is also:

f recover { case cause => throw new Exception("Something went wrong", cause) }

Since Scala 2.12 you can do:

f transform {
  case s @ Success(_) => s
  case Failure(cause) => Failure(new Exception("Something went wrong", cause))
}

or

f transform { _.transform(Success(_), cause => Failure(new Exception("Something went wrong", cause)))}

Solution 2

You could try recoverWith as in:

f recoverWith{
  case ex:Exception => Future.failed(new Exception("foo", ex))
}
Share:
25,132
theon
Author by

theon

Updated on May 11, 2020

Comments

  • theon
    theon almost 4 years

    What's the cleanest way to map the Exception of a failed Future in scala?

    Say I have:

    import scala.concurrent._
    import scala.concurrent.ExecutionContext.Implicits.global
    
    val f = Future { 
      if(math.random < 0.5) 1 else throw new Exception("Oh no") 
    }
    

    If the Future succeeds with 1, I'd like to keep that, however if it fails I would like to change the Exception to a different Exception.

    The best I could come up with is transform, however that requires me to make a needless function for the success case:

    val f2 = f.transform(s => s, cause => new Exception("Something went wrong", cause))
    

    Is there any reason there is no mapFailure(PartialFunction[Throwable,Throwable])?

  • Viktor Klang
    Viktor Klang over 10 years
    Future.failed is not evaluated on an ExeecutionContext: scala-lang.org/api/current/#scala.concurrent.Future$ see failed
  • cmbaxter
    cmbaxter over 10 years
    @ViktorKlang, I must be confused then. I had made this assumption in looking at the impl.KeptPromise class' onComplete method. In there, there are the two lines val preparedEC = executor.prepare; (new CallbackRunnable(preparedEC, func)).executeWithValue(completedAs). I assumed this to imply that even though we were giving an explicit value that it still for some reason was hitting the executor. It always seemed strange to me and I guess it's actually because I was misreading it. Thanks for the heads up.
  • theon
    theon over 10 years
    Thanks for the answers. My only hesitation with using recover/recoverWith is that when I see it I immediately assume that the intention is to recover from a failure with a successful result. Maybe that is just me. Even so they are good alternatives, thanks!
  • Jatin
    Jatin over 9 years
    @cmbaxter I still do not understand on how it doesn't hit ExecutionContext.
  • Kevin Meredith
    Kevin Meredith almost 9 years
    @cmbaxter - could you please check out my related question - stackoverflow.com/questions/31173982/….
  • MaatDeamon
    MaatDeamon over 8 years
    @theon The fact that you use an exception or something else to signal to your program that something failed should not matter i think. Hence using recover or recoverwith should be the way to go i presume.
  • theon
    theon over 8 years
    @MattDeomon Since it is a failure, I'd rather use an Exception, so it triggers onFailure callbacks rather than onSuccess callbacks. I think it is more intuitive that way. I still also find transform more intuitive than recover or recoverWith, because I am not recovering from a failure with a success, I am transforming a failure into another failure. That is true regardless of whether we use an Exception or a regular class to signal the failure.
  • owensmartin
    owensmartin almost 7 years
    While this is a very clear syntax, we still have to throw the new exception, instead of getting to map Throwable to Throwable. Is there a combinator for just that?