代码之家  ›  专栏  ›  技术社区  ›  Michel Krämer

捕获scala 2.8 rc1中的所有异常

  •  9
  • Michel Krämer  · 技术社区  · 15 年前

    我在文件中有以下伪scala代码 test.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
    

    所以,如果不建议使用catch all表达式,那么应该如何实现这样的模式呢?除此之外,为什么不建议这样的表达?

    4 回复  |  直到 11 年前
        1
  •  9
  •   Rex Kerr    15 年前

    警告存在是因为您可能不想捕获所有内容。例如,试图在 java.lang.Error 因为从这样的事情中往往很难恢复过来。(很有可能你会被抛出你的捕获块,还有一个例外。)

    此外,由于您不能有效地捕获所有内容,因此这不是实现原子/故障保护事务的安全方法。你最好有点像

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

    在新的 t 以确保它处于合理的状态。

        2
  •  2
  •   Ben Lings    15 年前

    我没有编译器来测试这个问题,但是在回滚事务之后,您不应该抛出异常吗?也就是说,这应该是

    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
  •  1
  •   Jeff    15 年前

    首先,注意这是一个警告,而不是一个错误。即便如此,只有-xstrict警告选项才会发出警告。换句话说,这意味着 也许吧 你在做逻辑错误,但这取决于你自己决定。

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

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

    即处理所有已知错误类型。

    但是如果您肯定希望忽略(或以同样的方式处理)所有可能的异常,那么只需忽略警告。

        4
  •  1
  •   Martin    11 年前

    你必须抓住 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
    

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