简体   繁体   English

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

[英]Throwing exceptions in Scala, what is the “official rule”

I'm following the Scala course on Coursera. 我正在关注Coursera的Scala课程。 I've started to read the Scala book of Odersky as well. 我也开始阅读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. 我经常听到的是,在函数式语言中抛出异常并不是一个好主意,因为它会破坏控制流,我们通常会返回一个带有失败或成功的Either。 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... 我也注意到方法断言/要求......

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? 有人可以解释一下我应该在哪种情况下使用什么?

The basic guideline is to use exceptions for something really exceptional**. 基本准则是使用异常来实现非常特殊的**。 For an "ordinary" failure, it's far better to use Option or Either . 对于“普通”故障,使用OptionEither要好得多。 If you are interfacing with Java where exceptions are thrown when someone sneezes the wrong way, you can use Try to keep yourself safe. 如果您正在与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. 好吧,像 segfault *堆栈溢出一样戏剧性和危险的东西,或者找不到像元素一样的东西。 You'd let the segfault stack 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 )? 你让 segfault 堆栈溢出抛出一个异常,但如果你只是找不到一个元素,为什么不返回一个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 Either is 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: Option for it worked / didn't, in cases where not working is expected behavior, not a shocking and alarming failure; 所以你有三种方法(至少)可以处理不同类型的失败:它的Option是否有效,如果没有工作是预期的行为,不是令人震惊和惊人的失败; Either for 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; Either对于当事情可以工作或没有(或者,真的,在这里你有两个相互排斥的选项任何情况下),并要保存什么地方出了错一些信息; and Try when you don't want the whole headache of exception handling yourself, but still need to interface with code that is exception-happy. 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; * 编辑:Segfaults崩溃JVM,不管字节码如何都不应该发生; 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. ** 编辑:异常(没有堆栈跟踪)也用于在斯卡拉控制流-其实当当的比较有效的机制,它们使之类的库定义的break语句和return ,从您的方法返回即使控件实际上已经传递到一个或多个闭包中。 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. 大多数情况下,你不应该自己担心,除了意识到捕获所有 Throwable并不是一个超级想法,因为你可能会错误地捕获其中一个控制流异常。

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. 因此,这是Scala专门用于转换功能纯度的地方之一,以便从传统语言和环境(特别是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. (当然,非终止递归也是如此,但是很少有语言愿意强制执行那些使这些不可能的限制。)为了保持功能纯度,你使用Option / Maybe / Either / Try / Validation,所有这些都编码成功或者作为引用透明类型的失败,并使用它们提供的各种高阶函数或基础语言特殊的monad语法来使事情更清楚。 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. 或者,在Scala中,你可以简单地决定放弃功能纯度,知道它可能会在短期内使事情变得更容易,但在长期内会更加困难。 This is similar to using "null" in Scala, or mutable collections, or local "var"s. 这类似于在Scala,可变集合或本地“var”中使用“null”。 Mildly shameful, and don't do to much of it, but everyone's under deadline. 轻微的可耻,并没有做太多,但每个人都在截止日期。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM