在Scala中抛出异常,“官方规则” [英] Throwing exceptions in Scala, what is the "official rule"

查看:385
本文介绍了在Scala中抛出异常,“官方规则”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在跟随Coursera的Scala课程。
我已经开始阅读Odersky的Scala书。



我经常听到的是,在功能语言中抛出异常并不是个好主意,因为它打破了控制流程,我们通常返回失败或成功。
似乎也可以说Scala 2.10将提供在这个方向上的Try。



但是在这本书和课程中,Martin Odersky似乎没有说(至少现在)异常是坏的,他使用它们很多。
我也注意到方法assert / require ...



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



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

解决方案

基本原则是为异常情况使用异常**。对于普通失败,使用 Option 或者更好。如果您正在与Java连接,当有人打喷嚏时出现异常,您可以使用尝试来保护自己的安全。



让我们举一些例子。



假设你有一种从地图中获取东西的方法。什么可能出错?那么,像 segfault *堆栈溢出的一些戏剧性和危险性的东西,或者没有找到类似于元素的东西。你会让 segfault 栈溢出引发异常,但是如果你只是找不到一个元素,为什么不返回一个 Option [V] 而不是值或异常(或 null )?



现在假设你正在编写一个程序,用户应该输入文件名。现在,如果您不仅仅是在出现错误的情况下立即保释该程序,那么一个 是要走的路:

  def main(args:Array [String]){
val f = {
if(args.length< 1)Left(没有文件名)
else {
val file = new File(args(0))
if(!file.exists)Left(File does not exist:+ args ))
else右(文件)
}
}
// ...
}

现在假设您要解析一个空格分隔的数字的字符串。

  val numbers =1 2 3 fish 5 6// Uh-oh 
// numbers.split().map(_。toInt)< - 将抛出异常!
val尝试= numbers.split().map(s => Try(s.toInt))//抓住它!
val good =试着收集{case Success(n)=>所以你有三种方式来处理不同类型的失败:选项为它工作/没有,如果不工作是预期的行为,不是令人震惊和惊人的失败; 当事情可以工作(或者,真的,任何情况下,你有两个相互排斥的选项),并且你想保存一些关于出了什么问题的信息,尝试,当你不想让自己的整个头痛的异常处理,但仍然需要与异常快乐的代码进行接口。



顺便说一句,例外是很好的例子,所以你会发现他们在教材或学习材料中比其他地方更频繁,我认为:教科书的例子经常是不完整的,这意味着正常的严重问题将通过谨慎的设计来防止它被抛出异常来标记。



* 编辑:Segfaults崩溃了JVM,而不管字节码如何;即使是例外也不会帮助你。我的意思是堆栈溢出。



** 编辑:Scala中的控制流也被用于异常(没有堆栈跟踪)实际上是一个非常有效的机制,并且它们使得可以像图书馆定义的 break 语句和返回即使控件实际上已经传递到一个或多个关闭。大多数情况下,你不应该担心自己,除非意识到抓住所有 Throwable 不是一个超级的想法,因为你可能会抓住一个的这些控制流程异常错误。


I'm following the Scala course on Coursera. I've started to read the Scala book of Odersky as well.

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.

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. If you are interfacing with Java where exceptions are thrown when someone sneezes the wrong way, you can use Try to keep yourself safe.

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 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)?

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:

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; 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; 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.

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.

**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 Throwables is not such a super idea since you might catch one of these control flow exceptions by mistake.

这篇关于在Scala中抛出异常,“官方规则”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆