Поймайте все исключения в Scala 2.8 RC1

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

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

9
задан Michel Krämer 27 April 2010 в 18:48
поделиться

3 ответа

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

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

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

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

9
ответ дан 2 November 2019 в 23:06
поделиться

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

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

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

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

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

1
ответ дан 2 November 2019 в 23:06
поделиться

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

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
}
2
ответ дан 2 November 2019 в 23:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: