it-swarm.com.de

Multiple oder Single Try Catch

Ich arbeite gerade daran, einen Teil meines Codes aufzuräumen, und ich kam an einen Punkt, an dem ich nicht wusste, welche Route besser wäre.

Momentan habe ich einen einzigen Try-Catch-Block für die Mehrheit meiner Methode. Am Ende werden einige Ausnahmen behandelt, aber ich dachte, mehr Try-Catch-Blöcke wären nur für die Wartung besser geeignet. Als ich jedoch den Code zerlegte, kam ich an einen Punkt, an dem ich mehrere Blöcke für dieselbe Art von Ausnahme schrieb. Ich kann die Upside-Seite für das Schreiben eines Blocks für jeden Teil sehen, da ich dann weitere Einzelheiten dazu geben kann, warum er fehlgeschlagen ist.

Meine Frage ist folgende: Gibt es da einen Nachteil? Könnte es Performanceprobleme oder ein anderes verstecktes Monster geben, das ich nicht sehe?

Was ist der bevorzugte Weg, mehrere Ausnahmen in einer Methode zu behandeln? Gibt es einen Industriestandard? 

Zur besseren Verdeutlichung meines Standpunkts hier ein paar Pseudo-Codes

//multiple try catch for same exception
try {
     //some code here
} catch (MyException e) {
     //specific error message here
}
try {
     //some different code here
} catch (MyException e) {
     //more specific error message indicating a different issue
}
47
Shaded

Ich versuche immer, das Verschachteln zu reduzieren, um die Lesbarkeit und Wartbarkeit zu verbessern. Wenn Sie n try/catch-Blöcke haben, die jeweils den gleichen Ausnahmetyp behandeln, können Sie den Code, der die Ausnahme in Methoden werfen kann, nicht umgestalten. Dies würde etwa so aussehen:

try {
    firstBatchOfTricky();
    secondBatchOfTricky();
    ....
    nthBatchOfTricky();
} catch (ItWentBoomException e) {
   // recover from boom
} catch (ItWentBangException e) {
   // recover from bang
}

Dies ist viel lesbarer als mehrere Try/Catches. Beachten Sie, dass Ihre Methoden beschreiben sollten, was sie im Sinne von selbstdokumentierendem Code tun.

Da Sie über einen eigenen Ausnahmetyp verfügen, können Sie der Ausnahme die erforderlichen Daten hinzufügen, um verschiedene Aktionen im catch-Block auszuführen. Wenn Sie "spezifischere Nachricht" sagen, können Sie einfach die Ausnahme mit der detaillierten Nachricht auslösen. Sie sollten nicht mehrere Fangblöcke benötigen. Wenn Sie aufgrund des Ausnahmezustands drastisch unterschiedliche Vorgänge ausführen möchten, erstellen Sie einfach weitere Ausnahmetypen und Catch-Blöcke, aber nur einen try-Block, wie mein Pseudocode zeigt.

Wenn Sie die Ausnahme (n) nicht wiederherstellen können, sollten Sie den Code nicht mit catch-Blöcken überladen. Wirf eine Laufzeitausnahme und lass sie blubbern. (Guter Rat von @tony in den Kommentaren)

50
hvgotcodes

Dies ist keine Frage der Leistung oder der persönlichen Vorlieben: Es handelt sich um eine Frage der Funktionalität und Anforderungen.

Angenommen, ich schreibe:

Szenario 1:

try
{
  doThingA();
}
catch (SomeException panic)
{
  System.out.println("doThingA failed");
}
try
{
  doThingB();
}
catch (SomeException panic)
{
  System.out.println("doThingB failed");
}

Szenario 2:

try
{
  doThingA();
  doThingB();
}
catch (SomeException panic)
{
  System.out.println("doThingA or doThingB failed");
}

Diese beiden Szenarien sind nicht gleichwertig: Sie machen unterschiedliche Dinge. Wenn in doThingA die Ausnahme ausgelöst wird, wird doThingB in Szenario 1 noch ausgeführt. Wenn in doThingA die Ausnahme ausgelöst wird, wird doThingB nicht ausgeführt. Die Frage ist also nicht, welche bessere Leistung oder welcher lesbarerer Code ist, sondern sollte DoThingA noch ausgeführt werden, wenn doThingA fehlschlägt oder nicht?

Wenn Sie wirklich das zweite Verhalten wünschen, aber Sie möchten, dass der Benutzer durch verschiedene Meldungen informiert wird, was falsch gelaufen ist, sollten Sie entweder unterschiedliche Ausnahmen auslösen oder den Text der Nachricht in die Ausnahme einfügen, d.

void doThingA() throws SomeException
{
  ... whatever code ...
  if (theWorldIsAboutToEnd)
    throw new SomeException("doThingA failed");
}

Dann in der Catch-Klausel, anstatt einen konstanten String anzuzeigen, geben Sie SomeException.toString oder SomeException.getMessage an.

43
Jay

Wenn die Ausnahmen unterschiedlich gehandhabt werden können (andere Fehlermeldung usw.), können Sie sie separat abfangen. 

Wenn die Ausnahmetypen unterschiedlich sind, bedeutet das nicht, dass Sie separate try-Blöcke haben müssen. Sie können einen try-Block mit mehreren Catches verwenden.

4
jzd

Es ist völlig abhängig vom Szenario. Wenn Sie eine Menge Sachen ausführen, die eine Sicherheitsausnahme auslösen, und Sie dieses Szenario auf dieselbe Weise behandeln, können Sie dafür einen try-Block verwenden.

Allerdings ist die Verwendung vieler kleinerer Try/Catch-Blöcke meiner Meinung nach oft besser. Ein großer Try/Catch-Vorgang ist wie mehrere goto-Anweisungen, es sei denn, Sie können nicht sagen, woher die gotos kommen.

Wie können Sie beispielsweise unten feststellen, welche Methode zu Ausnahme1 und welche zu Ausnahme 2 gehen würde? Es ist in Ordnung, wenn es ein kleiner Block ist, aber sobald er größer wird, wird er sehr unlesbar.

try{
  doThing1();
  doThing2();
  doThing3();
  doThing4();
  doThing5();
  doThing6();
  doThing7();
  doThing8();
  doThing9();
} catch (Exception1 e){

} catch (Exception2 e){

}

Unten ist klarer.

try{
  doThing1();      
} catch (Exception1 e){ [...] } 
  doThing2();
  doThing3();
  doThing4();
  doThing5();
  doThing6();
  doThing7();
  doThing8();
try{
    doThing9();
} catch (Exception2 e){ [...] }
1
JasonG

Meine persönliche Präferenz ist ein einzelner Versuch, der mehrere Fangblöcke enthalten kann oder nicht. Meine Methoden sind in der Regel klein genug, wenn dies sinnvoll ist. Wenn Ihre Zeit zu lang wird, um praktisch zu sein, müssen Sie vielleicht über das Refactoring nachdenken.

Eine Sache zu catch-Blöcken: Wenn Ihr catch-Block die Stack-Ablaufverfolgung druckt oder neu protokolliert, würde ich sagen, dass Sie die Ausnahmebedingung besser in die Throws-Klausel der Methodensignatur aufnehmen und diese aufblähen lassen sollten. 

1
duffymo

Ich stimme dem allgemeinen Konsens der obigen Antworten zu, dass ein einzelner Try-Catch-Block besser ist. Wenn Ihre Methode jedoch lange genug ist, um sich diese Frage anzusehen, ist sie wahrscheinlich zu lang. Es ist möglicherweise einfacher, neue Methoden daraus zu extrahieren, wenn die Ausnahmebehandlung lokalisierter ist. Ich denke jedoch, dass es am besten ist, Methoden zu extrahieren, die einfach die Ausnahme auslösen und die Ausnahmebehandlung in der ursprünglichen Methode belassen - idealerweise in einem einzigen Try-Catch-Block.

1
Carl Manaster

Es sieht sehr alt aus. Meine Antwort würde es jedoch zu einem Relavent machen, da Java 7 in den letzten Tagen eine neue Funktion hinzugefügt hat, um mehrere Ausnahmeregelungen und den catch-Block hinzuzufügen. Dies würde die Menge an Code beseitigen und sieht sehr interessant aus. Ich stoße auf dieses link explianing über das try-with-resource -Konzept.

0
Krishna

Ausgezeichnete Frage. Ich werde sagen, dass Sie einen einzigen Try-Catch-Block verwenden sollten. Meine Überlegung: Wenn Sie einen Grund haben, Ihre Methode in mehrere try-catch-Blöcke zu unterteilen, sollten Sie wahrscheinlich darüber nachdenken, Ihre Methode in mehrere Methoden umzuwandeln, von denen jede einen eigenen try-catch-Block hat.

0
Bob Kaufman

Um sicherzugehen, verwenden Sie immer einzelne try-catch-Blöcke für jede auslösende Anweisung, da alle Anweisungen in einen try-Block geschrieben werden.

0
Deepak Vajpayee

Ich versuche, das Wiederholen des Codes möglichst zu vermeiden. Wenn also die Antwort auf einen bestimmten Ausnahmetyp gleich ist, dann fangen Sie sie einmal an.

0
BigMac66

Ich bevorzuge einen einzelnen Try-Catch-Block. Wenn die Länge der Methode sehr groß wird, ziehe ich es vor, die Methode in mehrere interne Methoden für die Modularität zu unterteilen.
Manchmal können Sie diese internen Methoden auch wiederverwenden.
Ich fühle auf diese Weise viel sauberer und besser für die Instandhaltung.

0
Swift-Tuttle

Es hängt von Ihrer Codelogik ab. Können Sie Ihren Prozess (Berechnung oder was auch immer) jederzeit unterbrechen, oder Sie können/sollten/müssen/müssen den Fluss und das Rollback steuern/benachrichtigen/bestätigen/was auch immer, wenn in einem bestimmten Schritt eine Fehlerbedingung angezeigt wird .

Wenn Sie einen einfachen RSS-Client implementieren, können Sie den gesamten Socket-Code in einem Block aufbewahren. Wenn Sie jedoch einen bittorrent-Client schreiben, benötigen Sie eine Zustandsmaschine und eine viel detailliertere Ausnahmebehandlung.

0
tomash