2010-04-28 5 views
9

Я следующий фиктивный код Scala в файле test.scala:перехватывать все исключения в Scala 2.8 RC1

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, как я должен реализовать такой шаблон? И кроме того, почему такие выражения не рекомендуются так или иначе?

ответ

9

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

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

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

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

+0

OK. Это работает для транзакций. Но что, если я хочу полностью игнорировать исключение, созданное методом только потому, что в данный момент это не имеет значения. –

+5

Вы можете 'catch {case _: Exception =>}'. 'Ошибка'' Throwable', но не 'Exception' - обычно лучше пройти. Если вы действительно имеете в виду: «Мне все равно, если я попытаюсь и не поймаю это, я, по крайней мере, хочу дать ему лучший результат», тогда вы можете жить с (строгим) предупреждающим сообщением. Вот почему это предупреждение, а не ошибка. –

+0

Да, это работает. Благодаря! Вы правы, что ловить «Ошибка» на самом деле не так, как я хочу :-) –

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 
} 
+0

Спасибо, но этот код по-прежнему приводит к вышеупомянутому предупреждению. –

+0

does 'case e => throw e' clear the callstack? –

1

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

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

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

т.е. ручка meaningfuly все известные типы ошибок.

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

1

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

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

Смежные вопросы