开发者

Scala catching confusion

开发者 https://www.devze.com 2023-02-27 20:06 出处:网络
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 co

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

0

精彩评论

暂无评论...
验证码 换一张
取 消