Reputation: 1511
In Scala, a typical use of pattern matching for exception handling (at least per sources like this and this) looks like the following:
Try(...) match {
case Success(_) => println("success")
case Failure(exc) => println(s"caught: $exc")
}
However, that pattern also catches any non-Exception
Throwable
s thrown in the try
block:
Try(throw new AssertionError("assertion error")) match {
case Success(_) => println("success")
case Failure(exc) => println(s"caught: $exc")
}
caught: java.lang.AssertionError: assertion error
In Java, at least, catching Throwable
without a compelling reason to do so is generally considered to be an anti-pattern. (This source offers the same counsel for Scala.)
One option to avoid silently catching Throwable
is to catch it and re-throw it:
Try(throw new AssertionError("assertion error")) match {
case Success(_) => println("success")
case Failure(exc : Exception) => println(s"caught: $exc")
case Failure(th) => throw th
}
It seems odd, though, that an extra re-throw is necessary to avoid catching non-Exception
Throwable
s (usually considered unrecoverable), and that letting such Throwable
s escape, implicit in Java-style try
/catch
syntax, must be implemented explicitly.
Is there a more succinct / idiomatic syntax for using pattern-matching for exception-handling in Scala, while avoiding inadvertently catching Throwable
?
Upvotes: 4
Views: 12210
Reputation: 51271
Because the recover()
method takes a PartialFunction, it can be used to filter for the type of Throwable
you want to handle. After that, you can let get
unwrap the Try
and retrieve a value if it was either a Success
or a handled Failure
, or it will re-throw if it's still a Failure
, i.e. not handled by recover()
.
val result = Try{
//code block here
}.recover{
case exc:Exception => ... //should return same type as Success
}.get //unwrap the Try, will throw if Throwable was not an Exception
Upvotes: 10