I am trying to learn how to use Try with for comprehensions in scala.
In the below sample code(result1),
if the last statement in for comprehension throws an unhandled exception, Code doesn't break and an Try[Int] is returned.
But, if the sequence of statements is changed in for comprehension (result2). A runtime exception is thrown.
package simpleTryExample
import scala.util.Try
object SimpleTryExample {
def main(args: Array[String]): Unit = {
val result1 = for {
a <- strToInt("3")
b <- strToInt("a")
} yield (a + b)
println("result1 is " + result1)
val result2 = for {
a <- strToInt("a")
b <- strToInt("3")
} yield (a + b)
println("result2 is " + result2)
}
def strToInt(s: String): Try[Int] = {
s match {
case "a" =>
println("input is a")
throw new RuntimeException("a not allowed")
case _ => println("other then a")
}
Try(s.toInt)
}
}
Output :-
other then a
input is a
Exception in thread "main" java.lang.RuntimeException: a not allowed
at simpleTryExample.SimpleTryExample$.strToInt(SimpleTryExample.scala:30)
at simpleTryExample.SimpleTryExample$.main(SimpleTryExample.scala:18)
at simpleTryExample.SimpleTryExample.main(SimpleTryExample.scala)
result1 is Failure(java.lang.RuntimeException: a not allowed)
input is a
I was expecting result2 to be a Try[Int] type. What i am doing wrong here ..?
The problem is that in your second example, you're throwing the exception before entering the Try[T]
context.
In your first example, when running strToInt("a")
, you're already in the context of a Try[T]
, since the code is desugered to:
strToInt("3").flatMap(_ => strToInt("a"))
Since the first invocation of strToInt
is successful, everything executed after it inside the for comprehension is in the context of a Try
. But, in the second example, we have the opposite:
strToInt("a").flatMap(_ => strToInt("3"))
strToInt("a")
will throw a RuntimeException
since we're still not in a Try
context, it is only applied when you try to parse s
to an Int
.
To avoid this altogether, move the try higher up before the pattern match:
def strToInt(s: String): Try[Int] = {
Try {
s match {
case "a" =>
println("input is a")
throw new RuntimeException("a not allowed")
case _ => println("other then a")
}
s.toInt
}
}
And now we get:
other then a
input is a
result1 is Failure(java.lang.RuntimeException: a not allowed)
input is a
result2 is Failure(java.lang.RuntimeException: a not allowed)