捕获Exception对象是否安全?

pfe*_*rel 6 casting scala exception

我使用依赖异常的Java库。下面的简化代码:

    try {
      val eventTime = eventTimeString.as[Date]
    } catch {
      case e: Exception =>
        logger.error(s"Can't parse eventTime from $eventTimeString", e)
        // take action for the bad Date string.
    }
Run Code Online (Sandbox Code Playgroud)

在Java中,我只捕获将字符串解析为Date的异常,就不会捕获其余的异常,因为它们可能是致命的。我的理解是,捕获Exception意味着捕获任何非致命/非严重的异常。既然不一样,那么抓捕Throwable是安全的,但是真的吗?使用此方法的理由是,未知异常可能从更深的堆栈中抛出,如果它们不是致命的,为什么不捕获所有异常。这一直是Java中的问题,在Java中很容易从您进行的直接调用中找到可能的异常,而从更深层的调用中很难找到。这是Scala解决方案的基本含义,是“捕获所有可恢复的异常”?

我的问题是;是上面的代码被认为是良好的Scala风格,是否“安全”,这比仅捕获Date转换为字符串的字符串要好。

Mar*_*lic 8

Try@LuisMiguelMejiaSuarez建议解决该问题的样式方面,它提供了一种更惯用的Scala样式,如下所示

Try(eventTimeString.as[Date]) match {
  case Success(eventTimeDate) => // work with eventTimeDate
  case Failure(e: IllegalArgumentException) => // work with e
  case Failure(e: NullPointerException) => // work with e
  ...
  case Failure(e) => // work with e
}
Run Code Online (Sandbox Code Playgroud)

从语法上看,它看起来并没有太大区别,但是从概念上讲,这是一个很大的转变,因为SuccessFailure表示常规,而不是某些例外的控制结构Success是一个值等7是值,而try-catch更象whileif-else控制设施。

包装可能Try由Java库提供的所有可能引发的库调用,我们可以利用收益糖来像这样链接调用

for {
  a <- Try(foo)
  b <- Try(bar)
  c <- Try(qux)
} yield {
  // work with a, b and c
}
Run Code Online (Sandbox Code Playgroud)

哪里

def foo: Int = {
  throw new TimeoutException("foo")
  42
}

def bar: String = {
  throw new IllegalArgumentException("bar")
  "hello"
}

def qux: Boolean = {
  throw new NullPointerException("qux")
  true
}
Run Code Online (Sandbox Code Playgroud)

我们可以按顺序阅读此链,而不必中断我们的思路,并尝试了解一些特殊的控制结构如何适合算法。

关于问题的安全性,可以说,我们不应捕获致命异常,例如LinkageError,并且确实Try与以下异常不匹配

VirtualMachineError
ThreadDeath
InterruptedException
LinkageError
ControlThrowable
Run Code Online (Sandbox Code Playgroud)

如它的构造方式所示

object Try {
  def apply[T](r: => T): Try[T] =
    try Success(r) catch {
      case NonFatal(e) => Failure(e)
    }
}
Run Code Online (Sandbox Code Playgroud)

这里NonFatal

object NonFatal {
   def apply(t: Throwable): Boolean = t match {
     case _: VirtualMachineError | _: ThreadDeath | _: InterruptedException | _: LinkageError | _: ControlThrowable => false
     case _ => true
   }

  def unapply(t: Throwable): Option[Throwable] = if (apply(t)) Some(t) else None
}
Run Code Online (Sandbox Code Playgroud)