Search code examples
scalaperformancecoding-styletry-catchcode-cleanup

Scala - Try transform vs match vs map method


I have read about transform method on Try and compare this method with other methods to figure out which one will be more clear for coding. I show you the code below

val value: Try[Int] = Try("1".toInt)
.transform(f => Success(f), e => Success(0))


val value2: Try[Int] = Try("1".toInt) match {
    case Success(f) => Success(f)
    case Failure(e) => Success(0)
}


val value3: Try[Int] = Try("1".toInt)
    .map(f => f)
    .recover {
      case e: Exception => 0
    }

I would like to know which one will be better in these cases and the reason why is it?

Thank you


Solution

  • If you want to recover from any (non-fatal) exception, it makes more sense for the result to be Int than Try[Int], since you know you have a success value, so the most idiomatic solution would look like this:

    scala> import scala.util.Try
    import scala.util.Try
    
    scala> val value4: Int = Try("1".toInt).getOrElse(0)
    value4: Int = 1
    

    If your actual logic is more complex, or you just prefer being really explicit, you could pattern match:

    scala> import scala.util.{ Failure, Success, Try }
    import scala.util.{Failure, Success, Try}
    
    scala> val value5: Int = Try("1".toInt) match {
         |   case Success(i) => i
         |   case Failure(_) => 0
         | }
    value5: Int = 1
    

    If for some reason you really want to end up with a Try[Int] even though you know it will always be a Success, I'd suggest using recover and NonFatal:

    scala> import scala.util.Try, scala.util.control.NonFatal
    import scala.util.Try
    import scala.util.control.NonFatal
    
    scala> val value5: Try[Int] = Try("1".toInt).recover {
         |   case NonFatal(_) => 0
         | }
    value5: scala.util.Try[Int] = Success(1)
    

    Note that this leaves out the unnecessary .map(f => f) from your value3, and also replaces the catch-all case e: Exception with Scala's NonFatal extractor, which won't match fatal exceptions like OutOfMemoryError (you generally can't recover from these exceptions, so you don't want to catch them here).

    Even in this case, though, it wouldn't be idiomatic to use transform, since you can express the operation with a less powerful combinator (recover), and you should always prefer the simplest solution that does what you need.

    There's not really any reason to return a Try[Int] here, though, so I'd just go with getOrElse.