Scala捕获Exception对象是否安全?

时间:2019-05-30 19:49:18

标签: scala exception casting

我使用依赖异常的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.
    }

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

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

1 个答案:

答案 0 :(得分:6)

@LuisMiguelMejiaSuarez提出的解决问题Try的样式方面,提供了一种更惯用的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
}

从语法上看,并没有太大区别,但是从概念上讲,这是一个很大的转变,因为SuccessFailure代表规则的,而不是某些特殊的控制结构Success是一个值,就像7是一个值,而try-catch更像是whileif-else控制工具。

包装任何可能抛出Try的库调用(例如由Java库提供),我们可以像这样使用for-yield糖来链接调用

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

其中

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

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

def qux: Boolean = {
  throw new NullPointerException("qux")
  true
}

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

关于问题的安全性,可以争论的是,我们不应捕获诸如LinkageError之类的致命异常,而实际上Try与以下异常均不匹配

VirtualMachineError
ThreadDeath
InterruptedException
LinkageError
ControlThrowable

constructed

所示
object Try {
  def apply[T](r: => T): Try[T] =
    try Success(r) catch {
      case NonFatal(e) => Failure(e)
    }
}

其中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
}