Scala catching confusion
I've recently seen code like this:
val maybeInt = catching(classOf[NFE]) opt arg.toInt
What is this opt
? An Option? Why isn't it using getOrElse to extract the valu开发者_JS百科e? In the above code, will maybeInt
be None if a NumberFormatException gets thrown?
catching
looks like it's some sort of method call, doesn't it? It is, but it actually returns an instance of a class Catch
; it doesn't directly take an argument. This class has two methods that are particularly useful for dealing with exceptions (and several more for catching multiple exceptions). The first is
def opt [U >: T] (body: ⇒ U) : Option[U]
which is being used here--you give it something that may throw an exception, and it will return Some(result)
if everything went okay, and None
if the targeted exception was caught:
scala> type NFE = NumberFormatException
defined type alias NFE
scala> import scala.util.control.Exception._
import scala.util.control.Exception._
scala> catching(classOf[NFE]).opt( "fish".toInt )
res0: Option[Int] = None
scala> catching(classOf[NFE]).opt( "42".toInt )
res1: Option[Int] = Some(42)
You can then deal with this with map
or filter
or getOrElse
or whatever else you use to deal with options.
The other useful method is either
, which returns an instance of Left(exception)
if an exception was thrown, and a Right(result)
if it was not:
scala> catching(classOf[NFE]).either( "fish".toInt )
res2: Either[Throwable,Int] = Left(java.lang.NumberFormatException: For input string: "fish")
scala> catching(classOf[NFE]).either( "42".toInt )
res3: Either[Throwable,Int] = Right(42)
You can then use fold
or map to an option or whatever else you like doing with eithers.
Note that you can define a single catcher and use it multiple times (so you don't need to create the catcher object every time you, for example, parse an integer):
scala> val catcher = catching(classOf[NFE])
catcher: util.control.Exception.Catch[Nothing] = Catch(java.lang.NumberFormatException)
scala> catcher.opt("42".toInt)
res4: Option[Int] = Some(42)
scala> catcher.opt("fish".toInt)
res5: Option[Int] = None
Edit: as Daniel points out in the comments, this still creates a temporary Catch[Option]
; given the method signatures, there isn't an easy way to just have it trap exceptions and generate options without creating any extra objects. This reminds me why I write my own methods to do exactly that:
def optNFE[T](t: => T) = try { Some(t) } catch {case nfe: NFE => None}
optNFE( "fish".toInt ) // gives None
optNFE( "42".toInt ) // gives Some(42)
I use a more simple pattern when there is only one catch :
try{
return args.split(" ").exists(line.startsWith _)
}catch {
case _ =>{//generic exception
logger.error("Error with line ${line} for ${ex.message}")
throw _
}
}
I'm definitely not yet a Scala pro, and I guess you could find shorter stuff
精彩评论