Scala 中 NonFatal 和 Exception 的区别

The difference between NonFatal and Exception in Scala

this article中说:

If you want to catch “everything” that would normally happen, then use NonFatal:

import scala.util.control.NonFatal

try {
  operation()
} catch {
  case NonFatal(e) => errorHandler(e)
}

不过我一般用Exception:

try {
  operation()
} catch {
  case e: Exception => errorHandler(e)
}

我想知道 Scala 中 NonFatalException 有什么区别? Scala 中的 Exception 是否包含致命异常?

AFAIK in java,Exception 用于非致命错误,Error 用于致命错误。 Scala 在 Exception 方面与 java 不同吗?

捕获非致命异常的正确方法是什么?

编辑: 更新为最新的 Scala 版本(2.11+ 对 NonFatal.apply 有不同的定义)。


NonFatal 只是一个方便的提取器,它在 scala.util.control:

中定义
object NonFatal {
   /**
    * Returns true if the provided `Throwable` is to be considered non-fatal, or false if it is to be considered fatal
    */
   def apply(t: Throwable): Boolean = t match {
     // VirtualMachineError includes OutOfMemoryError and other fatal errors
     case _: VirtualMachineError | _: ThreadDeath | _: InterruptedException | _: LinkageError | _: ControlThrowable => false
     case _ => true
   }
  /**
   * Returns Some(t) if NonFatal(t) == true, otherwise None
   */
  def unapply(t: Throwable): Option[Throwable] = if (apply(t)) Some(t) else None
}

JVM 上没有特殊的 "fatal" 种异常 - Error 并不总是 "fatal",它们只是一种特殊的内部异常。 "Fatal" 异常只是 NonFatal 定义中使用的异常列表。在这个术语中,除了 InterruptedException 之外的所有 Exception 都被认为是非致命的。考虑 InterruptedException fatal 是有意义的,因为这意味着线程被中断,所以如果你想处理它,你应该显式地处理它。

NonFatal 提取器也能正确处理 ControlThrowables。这些是由特殊控制传递函数抛出的异常,例如 breakable.

中的 break

Scala 中很少提及异常,但在处理意外故障时仍然会多次执行异常。

当我们寻找什么时候抓住java.lang.Error?多个答案,意见会出现,但让我们集中精力在公用部分。

一个合理的应用应该不会尝试去捕获

  • "An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch."
  • "Thrown to indicate that the Java Virtual Machine is broken or has run out of resources necessary for it to continue operating."
  • "Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector."

NonFatal 是非致命 Throwable 的提取器。不会匹配 VirtualMachineError(例如,OutOfMemoryErrorWhosebugErrorVirtualMachineError 的子类)、ThreadDeathLinkageErrorInterruptedExceptionControlThrowable,这是合理的应用程序不应尝试捕获的故障的一部分。

考虑到这一点,我们可以编写代码来捕获所有无害的 Throwable 可以通过以下方式捕获:

try {
  // dangerous code
} catch {
  case NonFatal(e) => log.error(e, "Something not that bad.")
}

如果我们看一下 apply 方法,我们可以很清楚地看到它。

object NonFatal {
   /**
    * Returns true if the provided `Throwable` is to be considered non-fatal, or false if it is to be considered fatal
    */
   def apply(t: Throwable): Boolean = t match {
     // VirtualMachineError includes OutOfMemoryError and other fatal errors
     case _: VirtualMachineError | _: ThreadDeath | _: InterruptedException | _: LinkageError | _: ControlThrowable => false
     case _ => true
   }
}