Ist das Verschachteln von Try-Catch-Anweisungen immer noch ein Codegeruch, wenn es in einer Schleife verschachtelt ist?

8

Ich habe gehört, dass das Verschachteln von Try-Catch-Anweisungen oft ein Codegeruch sein kann, daher frage ich mich, ob diese Situation eine Ausnahme darstellt. Wenn nicht, welche guten Möglichkeiten zur Umgestaltung gibt es?

Mein Code sieht folgendermaßen aus:

try{
    X x = blah;
    otherStuff;
    for (int i = 0; i < N; i++){
        try{
            String y = Integer.toString(i);
            f(x);
        }
        catch(Exceptions1 e1){
            System.err.println(... + y + ...);
            System.exit(0);
        }
}
catch(Exceptions2 e2){
    ...
}

Ich benutze Exceptionshier, um einen Mehrfachfang anzuzeigen.

e2wird verwendet, um Ausnahmen zu fangen, die durch Initialisieren xund Ausführen ausgelöst werden otherStuff. Im Idealfall hätte mein Try-Catch nur diese beiden Zeilen umgeben, aber ich verwende sie xin meiner Schleife und wollte die Warnungen "nicht verwendete Zuweisung" vermeiden, die durch die Initialisierung auf Null außerhalb des Try-Catch verursacht werden.

e1wurde nicht mehrfach abgefangen, e2da ich dem Benutzer Informationen über Iterationsdetails bereitstellen möchte und daher einen catch-Block innerhalb der Schleife haben möchte.

Weasemunk
quelle

Antworten:

6

Wenn der e2Fang, wie Sie sagen, nur dazu dient, Fehler beim Initialisieren xund Ausführen zu erkennen, können otherStuffSie ihn in eine separate Methode extrahieren. Dies trennt auch die Logik gut und ermöglicht es Ihnen, möglicherweise einen aussagekräftigen Namen zu vergeben otherStuff.

public X Foo() {
    try{
        X x = blah;
        otherStuff;

        return x;
    }
    catch(Exceptions2 e2){
        ...
    }
}

public void Bar() {    
    X x = Foo();
    for (int i = 0; i < N; i++){
        try{
            String y = Integer.toString(i);
            f(x);
        }
        catch(Exceptions1 e1){
            System.err.println(... + y + ...);
            System.exit(0);
        }
    }
}
Martin Brenden
quelle
Diese Antwort war für meine Situation am sinnvollsten, da ich meinen Fehlerfang funktional trennen konnte, anstatt einen Alias ​​für den internen Fang
bereitzustellen
7

Sofern Sie nicht beabsichtigen, die gesamte innere Schleife zu verarbeiten, unabhängig davon, ob eine Ausnahme auftritt oder nicht, entspricht Ihr Code im Wesentlichen

try{
    X x = blah;
    otherStuff;
    for (...){ 
       f(x)
    }
}
catch(Exceptions1 e1){
    ...
}
catch(Exceptions2 e2){
    ...
}

das erfordert keine Verschachtelung.

Wenn Sie weiterhin die Behandlung innerer Ausnahmen benötigen, überarbeiten Sie die innere Ausnahme und ihre einschließende Methode in eine neue Methode. Dies hat auch den zusätzlichen Vorteil, dass Sie gezwungen sind, über andere Möglichkeiten zur Verarbeitung der inneren Schleife nachzudenken. Ausnahmen können in Bezug auf die Leistung sehr teuer werden, wenn viele von ihnen geworfen werden.

Robert Harvey
quelle
Ich verstehe was du meinst. Ich habe einige Details hinzugefügt, um meine Situation weiter zu spezifizieren. In der inneren Schleife möchte ich den Wert von y verwenden, der von der Iteration i abhängt (ich verwende tatsächlich a für jede, aber dies sollte meinen Standpunkt vermitteln). Mein innerer Fang sagt etwas über den Wert von y aus, wenn er gefangen wird, während der äußere Fang unabhängig von der Schleife ist. Kann ich die Verschachtelung immer noch umgehen oder bin ich durch meine Entscheidung, schleifenabhängige Informationen zu geben, eingeschlossen?
Weasemunk
Ich denke immer noch, ich würde die innere Schleife in eine eigene Methode umgestalten, mit der Sie mit Ausnahme der Möglichkeit tun können, was Sie wollen.
Robert Harvey
Vielen Dank, ich habe Ihre Antwort mit @Martin Brendans kombiniert, um eine saubere Lösung zu erstellen.
Weasemunk
3

Ich habe einige Bemerkungen zu Ihrer Frage:

  1. In dem von Ihnen angegebenen Beispiel benötigen Sie überhaupt keine Ausnahmen. Sie müssten nur die Zeichenfolge y überprüfen, Fehler protokollieren und die Schleife verlassen. Nichts ist außergewöhnlich daran, dass Sie ungültig sind und protokolliert werden müssen. Die Tatsache, dass Sie in diesem Fall Ausnahmen verwenden, ist ein Hinweis auf Codegeruch.

  2. Multi-Catch-Ausnahmen sind eigentlich nicht dazu gedacht, große Codestreifen zu verpacken und alles aufzufangen, was schief gehen könnte. Sie sollen helfen, zwischen Ausnahmen zu unterscheiden, wenn ein einzelner Codeabschnitt eine Reihe verschiedener Ausnahmen erzeugen kann. Da Sie Mutli-Catch-Ausnahmen als eine Art "Catch All" -Ansatz verwenden, weist dies auf Codegeruch hin.

  3. Es macht keinen Sinn, einen Try-Catch in die Schleife einzufügen, es sei denn, Sie planen, den Rest der Schleife weiter zu durchlaufen, selbst wenn für eines der Elemente eine Ausnahme gefunden wird. Ihr Beispielcode zeigt, dass Sie planen, die Schleife zu verlassen, wenn ein Element außergewöhnlich ist.

Ich denke, Sie könnten mit so etwas wie besser dran sein:

try
{
     var x = blah;
     DoStuff();
     foreach(var i in icollection) // i is an int
     {
          var y = SomethingDependentOnI(i);

          // check y for explicit exceptional states
          if (IsSomethingWrongWithY(y))
               throw new Exception1(y);
     }
}
catch (Exception1 e1)
{
}
catch (Exception2 e2)
{
}

Dies ist viel klarer, leidet aber immer noch unter den oben beschriebenen Problemen.

Preis Jones
quelle
Danke für den Kommentar. 1 + 2 waren in Bezug auf den tatsächlichen Code nicht wirklich relevant, aber ich denke, Ihre Perspektive bezüglich des Werfens innerhalb der Schleife macht Sinn
Weasemunk