2010-04-28 17 views
9

Ho il seguente codice Scala fittizia nel file test.scala:cattura tutte le eccezioni in 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() 
    } 
} 

Se ho compilare questo su Scala 2.8 RC1 con scalac -Xstrict-warnings test.scala Prendo il seguente avviso:

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

Quindi, se le espressioni catch-all non sono consigliate, come dovrei implementare tale modello invece? E a parte questo perché tali espressioni non sono comunque consigliate?

risposta

9

L'avviso esiste perché probabilmente non si vuole catturare tutto. Ad esempio, in genere è sconsigliabile provare a catturare qualcosa in java.lang.Error poiché è spesso difficile recuperare da tali cose. (È probabile che tu venga cacciato dal blocco catch con un'altra eccezione.)

Inoltre, poiché non è possibile catturare tutto in modo utile, questo non è un modo sicuro per implementare transazioni atomiche/failsafe. Si sta meglio con qualcosa di simile

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

con ulteriori test durante la lettura in una nuova t per assicurarsi che sia in uno stato ragionevole.

+0

OK. Questo funziona per le transazioni. Ma cosa succede se voglio ignorare completamente un'eccezione generata da un metodo solo perché non ha importanza a questo punto. –

+5

È possibile 'catch {case _: Exception =>}'. 'Errore' è' Throwable' ma non un 'Exception' - di solito meglio da seguire. Se intendi davvero, "Non mi interessa se cerco e non riesco a cogliere questo, voglio almeno dargli il mio colpo migliore", quindi puoi vivere con il (rigoroso) messaggio di avvertimento. Ecco perché è un avvertimento, non un errore. –

+0

Sì, funziona. Grazie! Hai ragione, che catturare l'errore non è proprio quello che voglio :-) –

2

Non ho un compilatore a disposizione per testarlo, ma non dovresti rilanciare l'eccezione dopo aver ripristinato la transazione? vale a dire questo dovrebbe essere

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

Se si sta recuperando tutte le eccezioni, si dovrebbe prendere atto di the documentation for ControlThrowable. Presumibilmente, si desidera che la transazione esegua il rollback della terminazione anomala, ma non si desidera che venga ripristinata per un ritorno non locale o util.control.Breaks.break. Se è così, si potrebbe voler fare qualcosa di simile al seguente:

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

Grazie, ma questo codice porta ancora al suddetto avvertimento. –

+0

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

1

Innanzitutto, si noti che si tratta di un avviso, non di un errore. E anche così, un avvertimento sollevato solo con l'opzione -Xstrict-warings. In altre parole, significa che forse stai facendo un errore logico, ma spetta a te decidere.

Come altri hanno notato, nella maggior parte dei casi non è significativo per catturare tutti eccezione e si dovrebbe fare qualcosa di simile:

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

tipi di errore cioè maniglia meaningfuly tutto noti.

Ma se si è certi che si desidera ignorare (o gestire allo stesso modo) tutte le possibili eccezioni, ignorare l'avviso.

1

devi prendere Throwable di dichiarare il vostro intento di catturare tutti:

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 

L'esempio di cui sopra, se da un pezzo di test di unità. Come dice l'avvertimento: sconsigliato nel normale codice

Problemi correlati