为什么Scala没有检查和未检查异常的概念?

时间:2016-12-09 09:07:14

标签: scala exception exception-handling

我有以下两个问题:

  1. 为什么Scala没有Checked和Un-checked异常的概念?
  2. 不支持已检查的例外有哪些优缺点?

2 个答案:

答案 0 :(得分:11)

我不知道Scala选择不检查异常的确切原因,但可以说是常见方法,您知道有多少其他语言检查除java以外的异常?

我会指出我多年来在很多java程序中看到的一些东西,我确信如果你认真对待java程序,你也会看到它。

try {
  // do stuff
} catch (Exception e) {
  throw new RuntimeException(e);
}

try {
  // do stuff
} catch (Exception e) {
  // do nothing
}

当然,你可以说这是懒惰的编程,而后者确实是。但它会向您显示一个问题,您有时可能无法处理异常,您希望程序中断,或者异常会冒泡到更高级别的组件来处理错误。

你现在可能正在思考你只需要在方法签名中添加投掷,但通常情况下你不能这样做。我可以使用java 8 lambdas给你一个明确的例子。

list.stream().map(item -> {
  // throws a checked exception. compilation error
  return normalizeItem(item);
});

在上面的代码中,您需要使用上面显示的两个技术中的一个来处理异常。你当然可以创建一个抛出异常的新功能界面,但是你需要重新创建所有标准的界面,只是为了用 throws 来激活它们。如果你问我,这真是一团糟。

我认为这是其中一个原因,scala从一开始就具有功能,并且检查异常并不顺利,正如您所看到的那样。

您可以阅读更全面的讨论here

答案 1 :(得分:6)

TL; DR跳转到最后一段:)

虽然我完全赞同蒂亚戈的答案,但有一些事情可以补充。 如您所知,Scala是一种功能性和面向对象的语言。 它的功能方面要求side-effects应该被消除,或者至少尽可能地减少Try

抛出异常是副作用,因为它不是引用透明的(即,它取决于抛出异常的上下文,例如,如果从try块内部抛出异常,它将被捕获​​,而如果它被抛出该try块之外,它将改变程序的流程)。

以下是本书 Scala中的函数式编程(P. Chiusano,R。Bjarnason)的一个例子

 def failingFn(i: Int): Int = {
       val y: Int = throw new Exception("fail!")
       try {
         val x = 42 + 5
         x + y
       }
       catch { case e: Exception => 43 }
 }

在上面的代码中,y不是引用透明的,因为如果用try块中的值替换它,函数的结果将是不同的。

好吧,对于所有的理论来说,上面的关键点是,抛出异常是一种副作用,这违反了函数式编程范式。为了解决这个问题,Scala的设计者决定返回“值”,表示发生了异常,而不是抛出异常。出于这个原因,引入了诸如{{3}}(及其直接子类型成功和失败)之类的类。您只需修改函数的返回类型,将其包装在Try中,而不是抛出异常。这会强制客户端检查成功或失败,而不会产生抛出异常带来的所有副作用。 Try类型的引入基本上替换了已检查的异常,因为通过使用Try返回类型,客户端在编译时隐式地意识到异常的可能性。