Поймай все исключения в Scala 2.8 RC1 - PullRequest
9 голосов
/ 28 апреля 2010

У меня есть следующий фиктивный код 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

Итак, если не рекомендуется использовать всеохватывающие выражения, как мне вместо этого реализовать такой шаблон? И кроме того, почему такие выражения так или иначе не рекомендуются?

Ответы [ 4 ]

9 голосов
/ 28 апреля 2010

Предупреждение существует, потому что вы, вероятно, не хотите поймать все. Например, вообще нецелесообразно пытаться поймать что-либо в java.lang.Error, так как от таких вещей часто трудно оправиться. (Скорее всего, вы будете выброшены из вашего блока catch с другим исключением.)

Кроме того, поскольку вы не можете все поймать, это не безопасный способ реализации атомарных / отказоустойчивых транзакций. Вам лучше с чем-то вроде

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

с дополнительным тестированием при чтении в новом t, чтобы убедиться, что оно находится в разумном состоянии.

2 голосов
/ 28 апреля 2010

У меня нет компилятора, чтобы проверить это, но не следует ли повторно вызывать исключение после отката транзакции? то есть это должно быть

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

Если вы перехватываете все исключения, вы должны принять к сведению документацию для 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
}
1 голос
/ 20 марта 2014

Вы должны поймать 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

Пример выше, если из части юнит-теста. Как говорится в предупреждении: не рекомендуется в нормальном коде

1 голос
/ 28 апреля 2010

Во-первых, обратите внимание, что это предупреждение, а не ошибка. И даже в этом случае предупреждение возникает только с опцией -Xstrict-warings. Другими словами, это означает, что возможно вы делаете логическую ошибку, но решать вам.

Как заметили другие, в большинстве случаев не имеет смысла отлавливать все исключения, и вы должны сделать что-то вроде этого:

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

т.е. полностью обрабатывать все известные типы ошибок.

Но если вы уверены, что хотите игнорировать (или обрабатывать одинаково) все возможные исключения, просто проигнорируйте предупреждение.

...