2010-04-28 11 views
9

Ich habe die folgende Dummy Scala Code in der Datei test.scala:fangen alle Ausnahmen 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() 
    } 
} 

Wenn ich kompilieren dies auf Scala 2.8 RC1 mit scalac -Xstrict-warnings test.scala Ich werde die folgende Warnung erhalten:

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

Also, wenn Catch-All-Ausdrücke nicht empfohlen werden, wie soll ich stattdessen ein solches Muster implementieren? Und warum werden solche Ausdrücke ohnehin nicht empfohlen?

Antwort

9

Die Warnung existiert, weil Sie wahrscheinlich nicht alles fangen wollen. Zum Beispiel ist es im Allgemeinen nicht ratsam, irgendetwas in java.lang.Error zu fangen, da es oft schwierig ist, sich von solchen Dingen zu erholen. (Die Chancen stehen gut, dass Sie mit einer anderen Ausnahme aus Ihrem catch-Block geworfen werden.)

Da Sie nicht alles sinnvoll abfangen können, ist dies keine sichere Methode, atomare/fehlersichere Transaktionen zu implementieren. Du bist besser dran mit so etwas wie

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

mit weiteren Tests unterziehen, wenn sie in einer neuen t lesen, um sicherzustellen, es in einem vernünftigen Zustand.

+0

OK. Dieser funktioniert für Transaktionen. Aber was, wenn ich eine durch eine Methode geworfene Ausnahme vollständig ignorieren möchte, nur weil es zu diesem Zeitpunkt keine Rolle spielt. –

+5

Sie können 'case _: Exception =>}'. 'Error' ist' Throwable', aber keine 'Exception' - normalerweise besser, um durchzugehen. Wenn du wirklich meinst: "Es ist mir egal, wenn ich versuche und versäume, das zu fangen, dann will ich wenigstens mein Bestes geben", dann kannst du mit der (strikten) Warnmeldung leben. Deshalb ist es eine Warnung, kein Fehler. –

+0

Ja, das funktioniert. Vielen Dank! Du hast recht, dass das Abfangen von "Error" nicht wirklich das ist, was ich will :-) –

2

Ich habe keinen Compiler zur Hand, um dies zu testen, aber sollten Sie nicht die Ausnahme nach dem Rollback der Transaktion erneut werfen? das heißt sollte diese

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

sein Wenn Sie alle Ausnahmen fangen, sollten Sie zur Kenntnis nehmen the documentation for ControlThrowable. Vermutlich möchten Sie, dass Ihre Transaktion bei einer abnormalen Beendigung zurückgesetzt wird, aber nicht für eine nicht lokale Rückgabe oder eine util.control.Breaks.break zurückgesetzt werden soll. Wenn ja, möchten Sie möglicherweise Folgendes tun:

+0

Danke, aber dieser Code führt immer noch zu der oben genannten Warnung. –

+0

wird 'case e => e 'den Callstack löschen? –

1

Beachten Sie zuerst, dass dies eine Warnung und kein Fehler ist. Und trotzdem wurde eine Warnung nur mit der Option -Xstrict-warings ausgelöst. Mit anderen Worten, es bedeutet, dass vielleicht Sie einen logischen Fehler machen, aber es liegt an Ihnen zu entscheiden.

Wie andere bemerkt haben, in den meisten Fällen ist es nicht sinnvoll, alle Ausnahme zu fangen, und Sie sollten etwas tun:

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

heißt Griff meaningfuly alle bekannten Fehlertypen.

Aber wenn Sie positiv sind, dass Sie alle möglichen Ausnahmen ignorieren (oder auf die gleiche Weise behandeln) wollen, ignorieren Sie einfach die Warnung.

1

Sie haben Throwable zu fangen Ihre Absicht alle fangen angeben:

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 

Das obige Beispiel, wenn aus einem Stück Unit-Test. Wie die Warnung sagt: nicht im normalen Code empfohlen