在Scala中抛出exception,什么是“官方规则”

我遵循Coursera的Scala课程。 我也开始阅读Odersky的Scala书。

我经常听到的是,在函数式语言中抛出exception不是一个好主意,因为它打破了控制stream程,而且我们通常会返回一个带有失败或成功的exception。 Scala 2.10似乎也会提供这个方向的Try。

但是在这本书和课程中,马丁·奥德斯基(Martin Odersky)似乎并没有(至less现在)说exception是不好的,他用了很多。 我也注意到方法断言/要求…

最后,我有点困惑,因为我想遵循最佳做法,但他们不清楚,语言似乎在双向…

有人可以解释我应该在哪种情况下使用?

基本的指导方针是使用例外的东西非常特殊**。 对于一个“普通”的失败,使用OptionEither要好得多。 如果您正在与Java接口,当有人打错了方式时抛出exception,您可以使用Try来保证自己的安全。

我们举一些例子。

假设你有一个从地图上取东西的方法。 有什么可能出错? 那么,像一个段错误*堆栈溢出,或像元素期望的东西戏剧性和危险的东西没有find。 你会让段错误栈溢出抛出一个exception,但如果你只是没有find一个元素,为什么不返回一个Option[V]而不是值或exception(或null )?

现在假设你正在编写一个用户应该input文件名的程序。 现在,如果您不是在出现问题时立即保释该程序,则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) } } // ... } 

现在假设你想用空格分隔的数字来parsing一个string。

 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 } 

所以,至less有三种方法可以处理不同types的失败:在没有正常工作的情况下,select这种方式是行不通的,而不是令人震惊和令人担忧的失败; Either是什么时候事情都可以工作(或者,实际上,在任何情况下,你有两个相互排斥的选项),你想保存一些关于错误的信息; 当你不想让自己的exception处理的头痛,但仍然需要与exception开心的代码接口。

顺便说一句,例外是一个很好的例子 – 所以你会发现他们更经常在教科书或学习材料比其他地方,我认为:教科书的例子往往是不完整的,这意味着严重的问题,通常会通过精心devise,以防止而是通过抛出exception来标记。

* 编辑:Segfaults崩溃的JVM,不应该发生,无论字节码; 即使是一个例外,也不会帮你。 我的意思是堆栈溢出。

** 编辑:exception(没有堆栈跟踪)也用于Scala中的控制stream – 它们实际上是一个非常有效的机制,并且它们允许像库定义的break语句和返回从你的方法返回的东西,即使该控制实际上已经通过一个或多个closures。 大多数情况下,你不应该担心这一点,除非意识到捕获所有的 Throwable并不是一个超级的想法,因为你可能会错误地捕获这些控制streamexception中的一个。

因此,这是Scala专门从function纯度转换为兼容性与遗留语言和环境(尤其是Java)的地方之一。 function纯度被例外所打破,因为它们打破了参照的完整性,使得不可能等同地推理。 (当然,非终止recursion也是这样做的,但很less有语言愿意强制实现那些不可能的限制。)为了保持function的纯净性,使用Option / Maybe / Either / Try / Validation,所有这些都可以编码成功或失败作为引用透明types,并使用它们提供的各种高级函数或底层语言特殊的monad语法来使事情更清晰。 或者,在斯卡拉,你可以简单地决定沟通function的纯度,知道它可以使事情变得更容易,但在更长的时间内更困难。 这与在Scala中使用“null”或可变集合或本地“var”类似。 轻度可耻的,不要做太多的事情,但每个人都在最后期限之下。