Home > Back-end >  Scala: Future recover in Future traverse
Scala: Future recover in Future traverse

Time:07-06

I have a method, which may throw an Exception depends on passed value:

 private def transform(in: Int): Future[Boolean] = in match {
    case i if i < 0 => Future.successful(true)
    case i if i > 0 => Future.successful(false)
    case i if i == 0 => throw new IllegalStateException()
 }

And second method, which apply above method to each element of List in parallel way.

def massTransform(ints: List[Int])(implicit ex: ExecutionContext): 
    Future[List[Boolean]] = {
            Future.traverse(ints){
               i => transform(i).recover {
                                           case e: IllegalStateException => false
                                          }
   }
}

I expected, recover will capture the IllegalStateException and return Future(false). But my code fails with IllegalStateException

CodePudding user response:

The problem is that you are throwing outside of a Future. You need to wrap your exception in a Future, otherwise what happens is that the method itself throws instead of returning a failed Future. You can simplify your method and simplify it as follows:

def transform(in: Int): Future[Boolean] =
  if (in == 0) Future.failed(new IllegalStateException)
  else Future.successful(in < 0)

You can play around with this code here on Scastie.

This looks like a simplification of your actual logic. If by any chance that's not (or not completely) the case, I can recommend removing the unnecessary Future nesting as follows:

def transform(in: Int): Boolean =
  if (in == 0) throw new IllegalStateException else in < 0

def massTransform(
    ints: List[Int]
)(implicit ex: ExecutionContext): Future[List[Boolean]] =
  Future(ints.map { i =>
    try transform(i)
    catch { case e: IllegalStateException => false }
  })

Notice how now the transform method throws and exception handling is done in the Future constructor.

You can play around with this second version on Scastie as well.

CodePudding user response:

transform is implemented in incorrectly, should be:

case i if i == 0 => Future.failed(new IllegalStateException())

I guess this is a simplified example, because this code does not really parallelise the computation btw, unless transform is in reality doing IO or quite expensive computation.

  • Related