scala 在Scala中抛出异常,什么是“官方规则”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12886285/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Throwing exceptions in Scala, what is the "official rule"
提问by Sebastien Lorber
I'm following the Scala course on Coursera. I've started to read the Scala book of Odersky as well.
我正在学习 Coursera 上的 Scala 课程。我也开始阅读 Odersky 的 Scala 书籍。
What I often hear is that it's not a good idea to throw exceptions in functional languages, because it breaks the control flow and we usually return an Either with the Failure or Success. It seems also that Scala 2.10 will provide the Try which goes in that direction.
我经常听到的是,在函数式语言中抛出异常不是一个好主意,因为它破坏了控制流,我们通常会返回一个带有失败或成功的要么。Scala 2.10 似乎也将提供朝这个方向发展的 Try。
But in the book and the course, Martin Odersky doesn't seem to say (at least for now) that exceptions are bad, and he uses them a lot. I also noticed the methods assert / require...
但是在这本书和课程中,Martin Odersky 似乎并没有说(至少现在)例外是不好的,他经常使用它们。我还注意到方法 assert / require ...
Finally I'm a bit confused because I'd like to follow the best practices but they are not clear and the language seems to go in both directions...
最后我有点困惑,因为我想遵循最佳实践,但它们不清楚,而且语言似乎是双向的......
Can someone explain me what i should use in which case?
有人可以解释我在这种情况下应该使用什么吗?
采纳答案by Rex Kerr
The basic guideline is to use exceptions for something really exceptional**. For an "ordinary" failure, it's far better to use Optionor Either. If you are interfacing with Java where exceptions are thrown when someone sneezes the wrong way, you can use Tryto keep yourself safe.
基本准则是对真正特殊的事物使用异常**。对于“普通”失败,最好使用Option或Either。如果您与 Java 交互,当有人以错误的方式打喷嚏时会抛出异常,您可以使用它Try来保证自己的安全。
Let's take some examples.
让我们举一些例子。
Suppose you have a method that fetches something from a map. What could go wrong? Well, something dramatic and dangerous like a segfault* stack overflow, or something expected like the element isn't found. You'd let the segfaultstack overflow throw an exception, but if you merely don't find an element, why not return an Option[V]instead of the value or an exception (or null)?
假设您有一个从地图中获取某些内容的方法。什么可能出错?那么,什么戏剧性和危险的像段错误*堆栈溢出,或预期的东西等等使元件没有找到。你让段错误堆栈溢出抛出一个异常,但如果你只是没有找到一个元素,为什么不返回Option[V],而不是价值或异常(或null)?
Now suppose you're writing a program where the user is supposed to enter a filename. Now, if you're not just going to instantly bail on the program when something goes wrong, an Eitheris the way to go:
现在假设您正在编写一个程序,用户应该在其中输入文件名。现在,如果您不只是在出现问题时立即放弃程序,那么可以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)
}
}
// ...
}
Now suppose you want to parse an string with space-delimited numbers.
现在假设您想解析一个以空格分隔的数字的字符串。
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 }
So you have three ways (at least) to deal with different types of failure: Optionfor it worked / didn't, in cases where not working is expected behavior, not a shocking and alarming failure; Eitherfor when things can work or not (or, really, any case where you have two mutually exclusive options) and you want to save some information about what went wrong; and Trywhen you don't want the whole headache of exception handling yourself, but still need to interface with code that is exception-happy.
所以你有三种方法(至少)来处理不同类型的失败:Option因为它有效/没有,在不工作是预期行为的情况下,不是一个令人震惊和令人震惊的失败;Either什么时候可以工作或不工作(或者,实际上,在您有两个互斥选项的任何情况下)并且您想保存一些关于出了什么问题的信息;并且Try当您不想自己处理异常的全部头痛时,但仍需要与异常高兴的代码接口时。
Incidentally, exceptions make for good examples--so you'll find them more often in a textbook or learning material than elsewhere, I think: textbook examples are very often incomplete, which means that serious problems that normally would be prevented by careful design ought instead be flagged by throwing an exception.
顺便说一下,例外是很好的例子——所以你会在教科书或学习材料中找到它们比在其他地方更常见,我认为:教科书的例子通常是不完整的,这意味着通常可以通过精心设计来防止的严重问题应该而是通过抛出异常来标记。
*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.
*编辑:段错误使 JVM 崩溃,无论字节码如何,都不应该发生;那么即使是例外也无济于事。我的意思是堆栈溢出。
**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 breakstatements and a returnthat 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 allThrowables is not such a super idea since you might catch one of these control flow exceptions by mistake.
**编辑:异常(没有堆栈跟踪)也用于 Scala 中的控制流——它们实际上是一种非常有效的机制,并且它们启用诸如库定义的break语句和return从您的方法返回的a 之类的东西,即使控制实际上已经进入一个或多个关闭。大多数情况下,您不应该自己担心这一点,除非意识到捕获所有Throwables 并不是一个好主意,因为您可能会错误地捕获这些控制流异常之一。
回答by Dave Griffith
So this is one of those places where Scala specifically trades off functional purity for ease-of-transition-from/interoperability-with legacy languages and environments, specifically Java. Functional purity is broken by exceptions, as they break referential integrity and make it impossible to reason equationally. (Of course, non-terminating recursions do the same, but few languages are willing to enforce the restrictions that would make those impossible.) To keep functional purity, you use Option/Maybe/Either/Try/Validation, all of which encode success or failure as a referentially-transparent type, and use the various higher-order functions they provide or the underlying languages special monad syntax to make things clearer. Or, in Scala, you can simply decide to ditch functional purity, knowing that it might make things easier in the short term but more difficult in the long. This is similar to using "null" in Scala, or mutable collections, or local "var"s. Mildly shameful, and don't do to much of it, but everyone's under deadline.
因此,这是 Scala 专门权衡功能纯度以方便从遗留语言和环境(特别是 Java)转换/互操作性的地方之一。异常破坏了功能纯洁性,因为它们破坏了参照完整性并使等式推理变得不可能。(当然,非终止递归也做同样的事情,但很少有语言愿意强制执行使这些成为不可能的限制。)为了保持功能的纯度,您可以使用 Option/Maybe/Either/Try/Validation,所有这些都编码成功或失败作为引用透明类型,并使用它们提供的各种高阶函数或底层语言的特殊 monad 语法使事情更清晰。或者,在 Scala 中,您可以简单地决定放弃函数纯度,知道这可能会在短期内使事情变得更容易,但从长远来看可能会变得更加困难。这类似于在 Scala 中使用“null”、可变集合或本地“var”。有点可耻,不要做太多,但每个人都在最后期限内。

