I really like scala.util.Try
in Scala 2.10, and how it works with for-comprehension makes handling multiple steps that could go wrong easily.
For example, we could use the following code to make sure we only print out that two numbers if and only if everything is under control and we get value correctly.
def tryA: Try[Int] = {....}
def tryB: Try[Int] = {....}
for {
a <- tryA
b <- tryB
} {
println (s"We got:${a+b}")
}
But one of my concern is that this code is actually ignore any exceptions, which means it will looks like the following try-cactch block:
try {
// .....
} catch {
case _: Exception => // Swallow any exception
}
As far as I know, there is an argument that this kind of codes is a bad smell, because no one will notice there is an exception occurs.
What I would like to achieve is that still using for
to make sure the println
only execute if everything is OK, but if there is any exception in any steps, it will blow up and throw out the exception directly.
Currently here is how I do this, but it seems less elegant because it introduce a new Try[Unit]
object, so I'm wondering how could I make this code better?
For example, is it possible to get rid of the result
variable and result.get
statement, but still get exception being thrown?
def tryA: Try[Int] = {....}
def tryB: Try[Int] = {....}
val result = for {
a <- tryA
b <- tryB
} yield {
println (s"We got:${a+b}")
}
result.get
To make thing more clear, it is the result from Scala REPL of the first code in this question.
scala> def tryA: Try[Int] = Success(1)
tryA: scala.util.Try[Int]
scala> def tryB: Try[Int] = Failure(new Exception("error"))
tryB: scala.util.Try[Int]
scala> for {
| a <- tryA
| b <- tryB
| } {
| println (s"We got:${a+b}")
| }
scala>
We can see that nothing happens here, even tryB
is a Failure
with exception. What I would like to get is an exception being thrown, and without the introduce the new Try[Unit]
object with yield
, is this possible?
You can use whatever you like, but Try/Success/Failure is generally used when dealing with code that can throw exceptions — because you almost always want to understand the exception — and Option/Some/None is used in other places, such as to avoid using null values.
The try/catch construct is different in Scala than in Java, try/catch in Scala is an expression. The exception in Scala and that results in a value can be pattern matched in the catch block instead of providing a separate catch clause for each different exception. Because try/catch in Scala is an expression.
Scala offers a lightweight notation for expressing sequence comprehensions. Comprehensions have the form for (enumerators) yield e , where enumerators refers to a semicolon-separated list of enumerators. An enumerator is either a generator which introduces new variables, or it is a filter.
The Try type represents a computation that may either result in an exception, or return a successfully computed value. It's similar to, but semantically different from the scala. util. Either type. Instances of Try[T] , are either an instance of scala.
You can use recover
:
import scala.util.Try
def tryEven = Try { val i = (math.random * 1000).toInt; if (i % 2 != 0) throw new Exception("odd") else i }
def tryEvenOrNeg1 = Try { val i = (math.random * 1000).toInt; if (i % 2 != 0) throw new Exception("odd") else i } recover { case exx: Exception => -1 }
scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b")
res1: scala.util.Try[Unit] = Failure(java.lang.Exception: odd)
scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b")
res2: scala.util.Try[Unit] = Failure(java.lang.Exception: odd)
scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b")
res3: scala.util.Try[Unit] = Failure(java.lang.Exception: odd)
scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b")
Got 542, -1
scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b")
res5: scala.util.Try[Unit] = Failure(java.lang.Exception: odd)
scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b")
res6: scala.util.Try[Unit] = Failure(java.lang.Exception: odd)
scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b")
Got 692, 750
I removed the resNN
that reflected Success(())
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With