方法返回一个 Option

1
2
3
4
5
6
7
def toInt(s: String): Option[Int] = {
try {
Some(Integer.parseInt(s.trim))
} catch {
case e: Exception => None
}
}

Option 中拿出一个值

有三种方法:

使用 getOrElse

将 None 的默认值放在 getOrElse 方法里。

1
2
scala> val x = toInt("1").getOrElse(0)
x: Int = 1

使用 foreach

由于 Option 是 0 个或者 1 个元素的集合,所以也可以用 foreach 方法来获取值:

1
2
scala> toInt("1").foreach(i => println)
1
  • 使用 match 模式匹配
1
2
3
4
5
scala> toInt("1") match {
case Some(i) => println(i)
case None => println("Not work")
}
1

使用 Try/Success/Failure 模式

Scala 2.10 中有了 scala.util.Try 方法,功能和使用方法和 Option 类似,但是允许在失败时返回具体的失败信息。

1
2
3
4
5
import scala.util.{Try, Success, Failure}

def divide(x: Int, y:Int): Try[Int] = {
Try(x/y)
}

只要 y 不是 0,上述方法会返回一个 Success 对象;如果 y 是 0,ArithmeticException 错误会发生,但是被 Try 方法捕获了,所以会返回一个 Failure 对象。

1
2
3
4
scala> divide(1,1)
res10: Try[Int] = Success(1)
scala> divide(1,0)
res11: Try[Int] = Failure(java.lang.ArithmeticException: / by zero)

Option 模式类似,也可以使用 getOrElse, foreach, match 三种方式获取成功的值或者失败的错误;

Try 模式还可以将链式的操作中的错误都捕获:

1
2
3
4
5
6
7
8
def multiply(x: String, y: String): Int = {
val z = for {
a <- Try(x.toInt)
b <- Try(y.toInt)
} yield a * b

z.getOrElse(0) * 2
}
1
2
3
4
scala> multiply("1", "2")
res0: Int = 4
scala> multiply("1", "xixi")
res1: Int = 0

Try 类还内置了很多实用的方法可以调用:

1
2
3
4
5
WithFilter         flatMap            getOrElse          productArity       recoverWith
canEqual flatten isFailure productElement toEither
collect fold isSuccess productIterator toOption
failed foreach map productPrefix transform
filter get orElse recover withFilter

可以研究一下。

使用 Either/Left/Right 模式

在 2.10 以前,Scala 使用功能和 Try/Success/Failure 类似的 Either/Left/Right 模式来做错误处理,其中,Right 对应 SuccessLeft 对应 Failure

一点讨论

Option 模式好用,唯一的缺点是不会返回错误的信息,另外,不要直接调用 Optionget 方法。

如果可能的话,直接使用 Try/Success/Failure 模式吧。

Reference

[1] https://alvinalexander.com/scala/best-practice-option-some-none-pattern-scala-idioms