基本准则是对真正异常的事情使用异常**。对于“普通”故障,最好使用Option
or Either
。如果您正在与 Java 进行交互,当有人以错误的方式打喷嚏时会抛出异常,您可以使用Try
确保自己的安全。
让我们举一些例子。
假设您有一个从地图中获取某些内容的方法。可能会出什么问题?嗯,一些戏剧性和危险的事情,比如 segfault* 堆栈溢出,或者一些预期的事情,比如找不到元素。您可以让 segfault 堆栈溢出抛出异常,但如果您只是找不到元素,为什么不返回一个Option[V]
而不是值或异常(或null
)?
现在假设您正在编写一个程序,用户应该在其中输入文件名。现在,如果您不打算在出现问题时立即退出该计划,Either
是要走的路:
def main(args: Array[String]) {
val f = {
if (args.length < 1) Left("No filename given")
else {
val file = new File(args(0))
if (!file.exists) Left("File does not exist: "+args(0))
else Right(file)
}
}
// ...
}
现在假设您想要解析一个以空格分隔的数字的字符串。
val numbers = "1 2 3 fish 5 6" // Uh-oh
// numbers.split(" ").map(_.toInt) <- will throw exception!
val tried = numbers.split(" ").map(s => Try(s.toInt)) // Caught it!
val good = tried.collect{ case Success(n) => n }
因此,您(至少)有三种方法来处理不同类型的故障:Option
因为它有效/无效,在不工作是预期行为的情况下,而不是令人震惊和令人震惊的失败;Either
当事情可以工作或不工作时(或者,实际上,您有两个相互排斥的选项的任何情况)并且您想要保存一些有关出错原因的信息;和Try
当您不想自己处理令人头疼的异常处理,但仍需要与支持异常的代码进行交互时。
顺便说一句,例外是很好的例子——所以你会在教科书或学习材料中比在其他地方更常见地发现它们,我认为:教科书的例子往往是不完整的,这意味着通常可以通过仔细设计来避免的严重问题应该相反,通过抛出异常来进行标记。
*Edit: Segfaults crash the JVM and should never happen regardless of the bytecode; even an exception won't help you then. I meant stack overflow.
**Edit: Exceptions (without a stack trace) are also used for control flow in Scala--they're actually quite an efficient mechanism, and they enable things like library-defined break
statements and a return
that returns from your method even though the control has actually passed into one or more closures. Mostly, you shouldn't worry about this yourself, except to realize that catching all Throwable
s is not such a super idea since you might catch one of these control flow exceptions by mistake.