【问题标题】:Catch all exceptions in Scala 2.8 RC1捕获 Scala 2.8 RC1 中的所有异常
【发布时间】:2011-02-13 04:49:42
【问题描述】:

我在文件 test.scala 中有以下虚拟 Scala 代码:

class Transaction {
  def begin() {}
  def commit() {}
  def rollback() {}
}

object Test extends Application {
  def doSomething() {}

  val t = new Transaction()
  t.begin()
  try {
    doSomething()
    t.commit()
  } catch {
    case _ => t.rollback()
  }
}

如果我在 Scala 2.8 RC1 上使用 scalac -Xstrict-warnings test.scala 编译它,我会收到以下警告:

test.scala:16: warning: catch clause swallows everything: not advised.
    case _ => t.rollback()
    ^
one warning found

所以,如果不建议使用包罗万象的表达式,我应该如何实现这样的模式呢?除此之外,为什么不建议这样的表达方式?

【问题讨论】:

    标签: scala warnings exception try-catch catch-all


    【解决方案1】:

    存在警告是因为您可能不想捕获所有内容。例如,通常不建议尝试捕获 java.lang.Error 中的任何内容,因为通常很难从这些内容中恢复。 (很有可能你会因为另一个异常而被赶出你的 catch 块。)

    此外,由于您无法有效地捕获所有内容,因此这不是实现原子/故障安全事务的安全方法。你最好用类似的东西

    try {
      t.commit()
    } finally {
      if (!t.checkCommitted()) {
        t.rollback()
        if (!t.checkRolledback()) throw new FUBARed(t)
      }
    }
    

    在读取新的t 时进行额外测试,以确保其处于合理状态。

    【讨论】:

    • 好的。这个适用于交易。但是,如果我想完全忽略一个方法抛出的异常,只是因为此时它并不重要。
    • 你可以catch { case _: Exception => }ErrorThrowable,但不是 Exception——通常更好。如果您的意思是“我不在乎我是否尝试并未能抓住它,我至少想尽力而为”,那么您可以接受(严格的)警告信息。这就是为什么它是一个警告,而不是一个错误。
    • 是的,这行得通。谢谢!你说得对,捕捉Error 并不是我真正想要的:-)
    • 对于包罗万象的处理程序,您可能应该更喜欢使用NonFatal(请参阅scala-lang.org/api/current/…)。这将更好地与 scala 集成。特别是,这不会干扰闭包内的返回,它在引擎盖下会抛出 NonLocalReturnControl
    • @RégisJean-Gilles - 事实上,这就是现在的方式。
    【解决方案2】:

    我没有编译器来测试这个,但你不应该在回滚事务后重新抛出异常吗?即这应该是

    val t = new Transaction()
    t.begin()
    try {
      doSomething()
      t.commit()
    } catch {
      case e => t.rollback(); throw e
    }
    

    如果您要捕获所有异常,则应注意the documentation for ControlThrowable。大概您希望您的事务在异常终止时回滚,但不希望它回滚以实现非本地返回或util.control.Breaks.break。如果是这样,您可能需要执行以下操作:

    val t = new Transaction()
    t.begin()
    try {
      doSomething()
      t.commit()
    } catch {
      case ce : ControlThrowable => throw ce // propagate
      case e => t.rollback(); throw e        // roll-back and propagate
    }
    

    【讨论】:

    • 谢谢,但这段代码仍然会导致上述警告。
    【解决方案3】:

    首先,请注意这是一个警告,而不是错误。即便如此,只有使用 -Xstrict-warings 选项才会发出警告。换句话说,这意味着可能你犯了一个逻辑错误,但由你来决定。

    正如其他人所注意到的,在大多数情况下,捕获所有异常是没有意义的,您应该这样做:

    t.begin()
    try {
      doSomething()
      t.commit()
    } catch {
      case e: DuplicatedKeyError => ...
      case e: BrokenConnectionError => ...
      case e: DumbInputDetectedError => ...
    }
    

    即有意义地处理所有已知的错误类型。

    但是,如果您确定要忽略(或以相同方式处理)所有可能的异常,则忽略警告。

    【讨论】:

      【解决方案4】:

      你必须抓住Throwable 来表明你想要抓住所有的意图:

        try {
           android.util.Log.i (TAG, "Feature " + Text)
           statements
        }
        catch {
           case exception: Throwable =>
              val Message = "Feature " + Text + "failed"
              android.util.Log.e (TAG, Message, exception)
              fail (Message)
        } // try
      

      上面的例子来自一个单元测试。正如警告所说:不建议在普通代码中

      【讨论】:

        猜你喜欢
        • 2014-02-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-01
        • 2011-11-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多