Sollte man versuchen ... innerhalb oder außerhalb einer Schleife zu fangen?

184

Ich habe eine Schleife, die ungefähr so ​​aussieht:

for (int i = 0; i < max; i++) {
    String myString = ...;
    float myNum = Float.parseFloat(myString);
    myFloats[i] = myNum;
}

Dies ist der Hauptinhalt einer Methode, deren einziger Zweck darin besteht, das Array von Floats zurückzugeben. Ich möchte, dass diese Methode zurückgegeben wird, nullwenn ein Fehler auftritt. Deshalb füge ich die Schleife try...catchwie folgt in einen Block ein:

try {
    for (int i = 0; i < max; i++) {
        String myString = ...;
        float myNum = Float.parseFloat(myString);
        myFloats[i] = myNum;
    }
} catch (NumberFormatException ex) {
    return null;
}

Aber dann dachte ich auch daran, den try...catchBlock so in die Schleife zu setzen :

for (int i = 0; i < max; i++) {
    String myString = ...;
    try {
        float myNum = Float.parseFloat(myString);
    } catch (NumberFormatException ex) {
        return null;
    }
    myFloats[i] = myNum;
}

Gibt es einen Grund, eine Leistung oder etwas anderes, einen dem anderen vorzuziehen?


Bearbeiten: Der Konsens scheint zu sein, dass es sauberer ist, die Schleife innerhalb des try / catch zu platzieren, möglicherweise innerhalb seiner eigenen Methode. Es gibt jedoch immer noch Debatten darüber, was schneller geht. Kann jemand dies testen und mit einer einheitlichen Antwort zurückkommen?

Michael Myers
quelle
2
Ich weiß nichts über die Leistung, aber der Code sieht mit dem try catch außerhalb der for-Schleife sauberer aus.
Jack B Nimble

Antworten:

131

PERFORMANCE:

Es gibt absolut keinen Leistungsunterschied, wo die Try / Catch-Strukturen platziert sind. Intern werden sie als Codebereichstabelle in einer Struktur implementiert, die beim Aufruf der Methode erstellt wird. Während die Methode ausgeführt wird, sind die Try / Catch-Strukturen nicht im Bild, es sei denn, es wird ein Wurf ausgeführt. Anschließend wird der Ort des Fehlers mit der Tabelle verglichen.

Hier ist eine Referenz: http://www.javaworld.com/javaworld/jw-01-1997/jw-01-hood.html

Die Tabelle ist etwa auf halber Höhe beschrieben.

Jeffrey L Whitledge
quelle
Okay, Sie sagen also, es gibt keinen Unterschied außer der Ästhetik. Können Sie auf eine Quelle verlinken?
Michael Myers
2
Vielen Dank. Ich nehme an, die Dinge haben sich seit 1997 geändert, aber sie würden es kaum weniger effizient machen.
Michael Myers
1
Absolut ist ein hartes Wort. In einigen Fällen können Compileroptimierungen verhindert werden. Keine direkten Kosten, aber es kann eine indirekte Leistungsstrafe sein.
Tom Hawtin - Tackline
2
Ich denke, ich hätte ein bisschen in meiner Begeisterung regieren sollen, aber die Fehlinformationen gingen mir auf die Nerven! Im Falle von Optimierungen, da wir nicht wissen können, auf welche Weise die Leistung beeinflusst werden würde, waren wir (wie immer) wieder beim Ausprobieren.
Jeffrey L Whitledge
1
Es gibt keinen Leistungsunterschied, nur wenn der Code ohne Ausnahmen ausgeführt wird.
Onur Bıyık
72

Leistung : Wie Jeffrey in seiner Antwort sagte, macht es in Java keinen großen Unterschied.

Für die Lesbarkeit des Codes hängt Ihre Wahl, wo die Ausnahme abgefangen werden soll, im Allgemeinen davon ab, ob die Schleife weiter verarbeitet werden soll oder nicht.

In Ihrem Beispiel sind Sie zurückgekehrt, als Sie eine Ausnahme abgefangen haben. In diesem Fall würde ich den Versuch / Fang um die Schleife legen. Wenn Sie einfach einen schlechten Wert abfangen möchten, aber die Verarbeitung fortsetzen möchten, legen Sie ihn ein.

Der dritte Weg : Sie können jederzeit Ihre eigene statische ParseFloat-Methode schreiben und die Ausnahmebehandlung in dieser Methode und nicht in Ihrer Schleife behandeln lassen. Die Ausnahmebehandlung auf die Schleife selbst isolieren!

class Parsing
{
    public static Float MyParseFloat(string inputValue)
    {
        try
        {
            return Float.parseFloat(inputValue);
        }
        catch ( NumberFormatException e )
        {
            return null;
        }
    }

    // ....  your code
    for(int i = 0; i < max; i++) 
    {
        String myString = ...;
        Float myNum = Parsing.MyParseFloat(myString);
        if ( myNum == null ) return;
        myFloats[i] = (float) myNum;
    }
}
Ray Hayes
quelle
1
Schau genauer hin. Er verlässt die erste Ausnahme in beiden Fällen. Das habe ich auch zuerst gedacht.
Kervin
2
Mir war bewusst, deshalb habe ich in seinem Fall gesagt, da er zurückkehrt, wenn er auf ein Problem stößt, würde ich eine externe Gefangennahme verwenden. Aus Gründen der Klarheit würde ich diese Regel
Ray Hayes
Netter Code, aber leider hat Java nicht den Luxus, Parameter zu verwenden.
Michael Myers
ByRef? Es ist so lange her, dass ich Java berührt habe!
Ray Hayes
2
Jemand anderes hat TryParse vorgeschlagen, mit dem Sie in C # /. Net eine sichere Analyse durchführen können, ohne Ausnahmen zu behandeln. Diese ist jetzt repliziert und die Methode ist wiederverwendbar. Was die ursprüngliche Frage betrifft, würde ich die Schleife innerhalb des Verschlusses bevorzugen, sie sieht nur sauberer aus, selbst wenn es kein Leistungsproblem gibt.
Ray Hayes
46

Nachdem Jeffrey L Whitledge gesagt hatte, dass es keinen Leistungsunterschied gibt (Stand 1997), habe ich ihn getestet. Ich habe diesen kleinen Benchmark durchgeführt:

public class Main {

    private static final int NUM_TESTS = 100;
    private static int ITERATIONS = 1000000;
    // time counters
    private static long inTime = 0L;
    private static long aroundTime = 0L;

    public static void main(String[] args) {
        for (int i = 0; i < NUM_TESTS; i++) {
            test();
            ITERATIONS += 1; // so the tests don't always return the same number
        }
        System.out.println("Inside loop: " + (inTime/1000000.0) + " ms.");
        System.out.println("Around loop: " + (aroundTime/1000000.0) + " ms.");
    }
    public static void test() {
        aroundTime += testAround();
        inTime += testIn();
    }
    public static long testIn() {
        long start = System.nanoTime();
        Integer i = tryInLoop();
        long ret = System.nanoTime() - start;
        System.out.println(i); // don't optimize it away
        return ret;
    }
    public static long testAround() {
        long start = System.nanoTime();
        Integer i = tryAroundLoop();
        long ret = System.nanoTime() - start;
        System.out.println(i); // don't optimize it away
        return ret;
    }
    public static Integer tryInLoop() {
        int count = 0;
        for (int i = 0; i < ITERATIONS; i++) {
            try {
                count = Integer.parseInt(Integer.toString(count)) + 1;
            } catch (NumberFormatException ex) {
                return null;
            }
        }
        return count;
    }
    public static Integer tryAroundLoop() {
        int count = 0;
        try {
            for (int i = 0; i < ITERATIONS; i++) {
                count = Integer.parseInt(Integer.toString(count)) + 1;
            }
            return count;
        } catch (NumberFormatException ex) {
            return null;
        }
    }
}

Ich habe den resultierenden Bytecode mit javap überprüft, um sicherzustellen, dass nichts inline wurde.

Die Ergebnisse zeigten, dass Jeffrey unter der Annahme unbedeutender JIT-Optimierungen korrekt ist . Es gibt absolut keinen Leistungsunterschied unter Java 6, Sun Client VM (ich hatte keinen Zugriff auf andere Versionen). Die Gesamtzeitdifferenz liegt während des gesamten Tests in der Größenordnung von einigen Millisekunden.

Daher ist die einzige Überlegung, was am saubersten aussieht. Ich finde, dass der zweite Weg hässlich ist, also werde ich mich entweder an den ersten Weg oder an Ray Hayes 'Weg halten .

Michael Myers
quelle
Wenn der Exception-Handler einen Flow außerhalb der Schleife nimmt, ist es meiner Meinung nach am klarsten, ihn außerhalb der Schleife zu platzieren - anstatt eine catch-Klausel anscheinend innerhalb der Schleife zu platzieren, die dennoch zurückkehrt. Ich verwende eine Leerzeichenzeile um den "gefangenen" Körper solcher "Fang-All" -Methoden, um den Körper klarer vom allumfassenden Try-Block zu trennen .
Thomas W
16

Während die Leistung gleich sein mag und das, was besser "aussieht", sehr subjektiv ist, gibt es immer noch einen ziemlich großen Unterschied in der Funktionalität. Nehmen Sie das folgende Beispiel:

Integer j = 0;
    try {
        while (true) {
            ++j;

            if (j == 20) { throw new Exception(); }
            if (j%4 == 0) { System.out.println(j); }
            if (j == 40) { break; }
        }
    } catch (Exception e) {
        System.out.println("in catch block");
    }

Die while-Schleife befindet sich innerhalb des try catch-Blocks. Die Variable 'j' wird inkrementiert, bis sie 40 erreicht. Sie wird ausgedruckt, wenn j mod 4 Null ist, und eine Ausnahme wird ausgelöst, wenn j 20 erreicht.

Vor allen Details hier das andere Beispiel:

Integer i = 0;
    while (true) {
        try {
            ++i;

            if (i == 20) { throw new Exception(); }
            if (i%4 == 0) { System.out.println(i); }
            if (i == 40) { break; }

        } catch (Exception e) { System.out.println("in catch block"); }
    }

Dieselbe Logik wie oben, der einzige Unterschied besteht darin, dass sich der try / catch-Block jetzt innerhalb der while-Schleife befindet.

Hier kommt die Ausgabe (während in try / catch):

4
8
12 
16
in catch block

Und die andere Ausgabe (try / catch in while):

4
8
12
16
in catch block
24
28
32
36
40

Da haben Sie einen ganz signifikanten Unterschied:

während in try / catch aus der Schleife ausbricht

try / catch in, während die Schleife aktiv bleibt

seBaka28
quelle
So setzte try{} catch() {}um die Schleife , wenn die Schleife als eine einzige „Einheit“ behandelt wird und die Suche nach einem Problem, dass Einheit der ganze „Einheit“ (oder Schleife in diesem Fall) macht nach Süden gehen. Setzen try{} catch() {}innerhalb der Schleife , wenn sie eine einzige Iteration der Schleife oder ein einzelnes Element in einem Array als Ganzes „Einheit“ behandeln. Wenn eine Ausnahme in dieser "Einheit" auftritt, überspringen wir einfach dieses Element und fahren dann mit der nächsten Iteration der Schleife fort.
Galaxy
14

Ich bin mit allen Beiträgen zur Leistung und Lesbarkeit einverstanden. Es gibt jedoch Fälle, in denen es wirklich wichtig ist. Ein paar andere Leute erwähnten dies, aber es könnte einfacher sein, anhand von Beispielen zu sehen.

Betrachten Sie dieses leicht modifizierte Beispiel:

public static void main(String[] args) {
    String[] myNumberStrings = new String[] {"1.2345", "asdf", "2.3456"};
    ArrayList asNumbers = parseAll(myNumberStrings);
}

public static ArrayList parseAll(String[] numberStrings){
    ArrayList myFloats = new ArrayList();

    for(int i = 0; i < numberStrings.length; i++){
        myFloats.add(new Float(numberStrings[i]));
    }
    return myFloats;
}

Wenn Sie möchten, dass die parseAll () -Methode bei Fehlern (wie im Originalbeispiel) null zurückgibt, setzen Sie den try / catch wie folgt nach außen:

public static ArrayList parseAll1(String[] numberStrings){
    ArrayList myFloats = new ArrayList();
    try{
        for(int i = 0; i < numberStrings.length; i++){
            myFloats.add(new Float(numberStrings[i]));
        }
    } catch (NumberFormatException nfe){
        //fail on any error
        return null;
    }
    return myFloats;
}

In Wirklichkeit sollten Sie hier wahrscheinlich einen Fehler anstelle von null zurückgeben, und im Allgemeinen mag ich es nicht, mehrere Rückgaben zu haben, aber Sie haben die Idee.

Wenn Sie jedoch möchten, dass die Probleme einfach ignoriert werden und alle möglichen Zeichenfolgen analysiert werden, setzen Sie den Versuch / Fang wie folgt auf die Innenseite der Schleife:

public static ArrayList parseAll2(String[] numberStrings){
    ArrayList myFloats = new ArrayList();

    for(int i = 0; i < numberStrings.length; i++){
        try{
            myFloats.add(new Float(numberStrings[i]));
        } catch (NumberFormatException nfe){
            //don't add just this one
        }
    }

    return myFloats;
}
Matt N.
quelle
2
Deshalb sagte ich: "Wenn Sie einfach einen schlechten Wert abfangen möchten, aber die Verarbeitung fortsetzen möchten, legen Sie ihn hinein."
Ray Hayes
5

Wie bereits erwähnt, ist die Leistung gleich. Die Benutzererfahrung ist jedoch nicht unbedingt identisch. Im ersten Fall schlagen Sie schnell fehl (dh nach dem ersten Fehler). Wenn Sie jedoch den try / catch-Block in die Schleife einfügen, können Sie alle Fehler erfassen, die für einen bestimmten Aufruf der Methode erstellt würden. Wenn Sie ein Array von Werten aus Zeichenfolgen analysieren, bei denen Formatierungsfehler zu erwarten sind, gibt es definitiv Fälle, in denen Sie dem Benutzer alle Fehler anzeigen möchten, damit er nicht versuchen muss, sie einzeln zu beheben .

user19810
quelle
Dies gilt nicht für diesen speziellen Fall (ich kehre in den Fangblock zurück), aber es ist eine gute Sache, dies im Allgemeinen zu beachten.
Michael Myers
4

Wenn alles oder nichts fehlschlägt, ist das erste Format sinnvoll. Wenn Sie alle nicht fehlerhaften Elemente verarbeiten / zurückgeben möchten, müssen Sie das zweite Formular verwenden. Das wären meine grundlegenden Kriterien für die Wahl zwischen den Methoden. Persönlich würde ich, wenn es alles oder nichts ist, die zweite Form nicht verwenden.

Joe Skora
quelle
4

Solange Sie wissen, was Sie in der Schleife erreichen müssen, können Sie den try catch außerhalb der Schleife platzieren. Es ist jedoch wichtig zu verstehen, dass die Schleife dann endet, sobald die Ausnahme auftritt, und dass dies möglicherweise nicht immer das ist, was Sie möchten. Dies ist tatsächlich ein sehr häufiger Fehler in Java-basierter Software. Die Benutzer müssen eine Reihe von Elementen verarbeiten, z. B. das Leeren einer Warteschlange, und sich fälschlicherweise auf eine äußere try / catch-Anweisung verlassen, die alle möglichen Ausnahmen behandelt. Sie könnten auch nur eine bestimmte Ausnahme innerhalb der Schleife behandeln und keine andere Ausnahme erwarten. Wenn dann eine Ausnahme auftritt, die nicht innerhalb der Schleife behandelt wird, wird die Schleife "vorbelegt", sie endet möglicherweise vorzeitig und die äußere catch-Anweisung behandelt die Ausnahme.

Wenn die Schleife im Leben die Aufgabe hatte, eine Warteschlange zu leeren, könnte diese Schleife sehr wahrscheinlich enden, bevor diese Warteschlange wirklich geleert wurde. Sehr häufiger Fehler.

Gunnar Forsgren - Mobimation
quelle
2

In Ihren Beispielen gibt es keinen funktionalen Unterschied. Ich finde Ihr erstes Beispiel besser lesbar.

Jamie
quelle
2

Sie sollten die äußere Version der inneren Version vorziehen. Dies ist nur eine bestimmte Version der Regel. Verschieben Sie alles außerhalb der Schleife, was Sie außerhalb der Schleife verschieben können. Abhängig vom IL-Compiler und JIT-Compiler können Ihre beiden Versionen unterschiedliche Leistungsmerkmale aufweisen oder nicht.

In einem anderen Punkt sollten Sie sich wahrscheinlich float.TryParse oder Convert.ToFloat ansehen.

Orion Adrian
quelle
2

Wenn Sie den Versuch / Fang in die Schleife einfügen, wird die Schleife nach einer Ausnahme fortgesetzt. Wenn Sie es außerhalb der Schleife platzieren, werden Sie angehalten, sobald eine Ausnahme ausgelöst wird.

Joel Coehoorn
quelle
Nun, ich gebe ausnahmsweise null zurück, sodass die Verarbeitung in meinem Fall nicht fortgesetzt wird.
Michael Myers
2

Meine Perspektive wäre, dass Try / Catch-Blöcke notwendig sind, um eine ordnungsgemäße Ausnahmebehandlung sicherzustellen, aber das Erstellen solcher Blöcke hat Auswirkungen auf die Leistung. Da Schleifen intensive sich wiederholende Berechnungen enthalten, wird nicht empfohlen, Try / Catch-Blöcke in Schleifen einzufügen. Außerdem scheint es, dass dort, wo dieser Zustand auftritt, häufig "Exception" oder "RuntimeException" abgefangen wird. RuntimeException, die im Code abgefangen wird, sollte vermieden werden. Wenn Sie in einem großen Unternehmen arbeiten, ist es wichtig, diese Ausnahme ordnungsgemäß zu protokollieren oder die Laufzeitausnahme zu stoppen. Der springende Punkt dieser Beschreibung istPLEASE AVOID USING TRY-CATCH BLOCKS IN LOOPS

surendrapanday
quelle
1

Das Einrichten eines speziellen Stapelrahmens für Try / Catch erhöht den Overhead, aber die JVM kann möglicherweise die Tatsache erkennen, dass Sie zurückkehren, und diesen optimieren.

Abhängig von der Anzahl der Iterationen ist der Leistungsunterschied wahrscheinlich vernachlässigbar.

Ich stimme jedoch den anderen zu, dass der Loop-Körper sauberer aussieht, wenn er außerhalb der Schleife liegt.

Wenn die Möglichkeit besteht, dass Sie jemals mit der Verarbeitung fortfahren möchten, anstatt sie zu beenden, wenn eine ungültige Nummer vorliegt, möchten Sie, dass sich der Code in der Schleife befindet.

Matt
quelle
1

Wenn es innen ist, erhalten Sie den Overhead der Try / Catch-Struktur N-mal, im Gegensatz zu nur einmal außen.


Jedes Mal, wenn eine Try / Catch-Struktur aufgerufen wird, erhöht sich der Aufwand für die Ausführung der Methode. Nur ein bisschen Speicher- und Prozessor-Ticks, um mit der Struktur fertig zu werden. Wenn Sie eine Schleife 100 Mal ausführen und hypothetisch gesehen, nehmen wir an, dass die Kosten 1 Tick pro Try / Catch-Aufruf betragen. Wenn Sie Try / Catch in der Schleife haben, kosten Sie 100 Ticks, im Gegensatz zu nur 1 Tick, wenn dies der Fall ist außerhalb der Schleife.

Stephen Wrighton
quelle
Können Sie etwas näher auf den Overhead eingehen?
Michael Myers
1
Okay, aber Jeffrey L Whitledge sagt, dass es keinen zusätzlichen Aufwand gibt. Können Sie eine Quelle angeben, die besagt, dass es eine gibt?
Michael Myers
Die Kosten sind gering, fast vernachlässigbar, aber es ist da - alles hat Kosten. Hier ist ein Blog-Artikel von Programmer's Heaven ( tiny.cc/ZBX1b ) über .NET und hier ein Newsgroup-Beitrag von Reshat Sabiq über JAVA ( tiny.cc/BV2hS )
Stephen Wrighton
Ich verstehe ... Nun stellt sich die Frage, ob die Kosten für die Eingabe von try / catch anfallen (in diesem Fall sollte es außerhalb der Schleife liegen) oder ob sie für die Dauer des try / catch konstant sind (in diesem Fall) sollte in der Schleife sein)? Sie sagen, es ist die Nummer 1. Und ich bin immer noch nicht ganz davon überzeugt, dass es Kosten gibt.
Michael Myers
1
Laut diesem Google-Buch ( tinyurl.com/3pp7qj ) "zeigen die neuesten VMs keine Strafe".
Michael Myers
1

Der springende Punkt bei Ausnahmen ist, den ersten Stil zu fördern: Die Fehlerbehandlung einmal konsolidieren und behandeln zu lassen, nicht sofort an jeder möglichen Fehlerstelle.

wnoise
quelle
Falsch! Der Punkt der Ausnahmen besteht darin, zu bestimmen, welches außergewöhnliche Verhalten angenommen werden soll, wenn ein "Fehler" auftritt. Die Wahl des inneren oder äußeren Try / Catch-Blocks hängt also wirklich davon ab, wie Sie mit der Schleifenbehandlung umgehen möchten.
Gizmo
Dies kann ebenso gut mit Fehlerbehandlungen vor Ausnahmen durchgeführt werden, z. B. dem Übergeben von "Fehler aufgetreten" -Flaggen.
wnoise
1

tue es hinein. Sie können die Verarbeitung fortsetzen (wenn Sie möchten) oder eine hilfreiche Ausnahme auslösen, die dem Client den Wert von myString und den Index des Arrays mit dem fehlerhaften Wert mitteilt. Ich denke, NumberFormatException wird Ihnen bereits den schlechten Wert mitteilen, aber das Prinzip besteht darin, alle hilfreichen Daten in die Ausnahmen zu setzen, die Sie auslösen. Überlegen Sie, was Sie an dieser Stelle im Programm im Debugger interessieren würde.

Erwägen:

try {
   // parse
} catch (NumberFormatException nfe){
   throw new RuntimeException("Could not parse as a Float: [" + myString + 
                              "] found at index: " + i, nfe);
} 

In Zeiten der Not werden Sie eine Ausnahme wie diese mit möglichst vielen Informationen wirklich zu schätzen wissen.

Kyle Dyer
quelle
Ja, dies ist auch ein gültiger Punkt. In meinem Fall lese ich aus einer Datei. Alles, was ich wirklich brauche, ist die Zeichenfolge, die nicht analysiert werden konnte. Also habe ich System.out.println (ex) ausgeführt, anstatt eine weitere Ausnahme auszulösen (ich möchte so viel von der Datei analysieren, wie legal ist).
Michael Myers
1

Ich möchte meine eigenen 0.02czwei konkurrierenden Überlegungen hinzufügen, wenn ich das allgemeine Problem betrachte, wo die Ausnahmebehandlung positioniert werden soll:

  1. Die "größere" Verantwortung des try-catchBlocks (dh in Ihrem Fall außerhalb der Schleife) bedeutet, dass Sie beim Ändern des Codes zu einem späteren Zeitpunkt möglicherweise fälschlicherweise eine Zeile hinzufügen, die von Ihrem vorhandenen catchBlock behandelt wird. möglicherweise unbeabsichtigt. In Ihrem Fall ist dies weniger wahrscheinlich, da Sie explizit a fangenNumberFormatException

  2. Je "enger" die Verantwortung der try-catch Blocks ist, desto schwieriger wird das Refactoring. Insbesondere, wenn Sie (wie in Ihrem Fall) eine "nicht lokale" Anweisung aus dem catchBlock (der return nullAnweisung) ausführen .

oxbow_lakes
quelle
1

Das hängt von der Fehlerbehandlung ab. Wenn Sie nur die Fehlerelemente überspringen möchten, versuchen Sie es innen:

for(int i = 0; i < max; i++) {
    String myString = ...;
    try {
        float myNum = Float.parseFloat(myString);
        myFloats[i] = myNum;
    } catch (NumberFormatException ex) {
        --i;
    }
}

In jedem anderen Fall würde ich den Versuch draußen vorziehen. Der Code ist besser lesbar und sauberer. Vielleicht ist es besser, stattdessen eine IllegalArgumentException in den Fehlerfall zu werfen, wenn null zurückgegeben wird.

Arne Burmeister
quelle
1

Ich werde meine $ 0,02 eingeben. Manchmal müssen Sie später ein "endlich" in Ihren Code einfügen (denn wer schreibt den Code jemals beim ersten Mal perfekt?). In diesen Fällen ist es plötzlich sinnvoller, den Versuch / Fang außerhalb der Schleife zu haben. Beispielsweise:

try {
    for(int i = 0; i < max; i++) {
        String myString = ...;
        float myNum = Float.parseFloat(myString);
        dbConnection.update("MY_FLOATS","INDEX",i,"VALUE",myNum);
    }
} catch (NumberFormatException ex) {
    return null;
} finally {
    dbConnection.release();  // Always release DB connection, even if transaction fails.
}

Denn wenn Sie eine Fehlermeldung erhalten oder nicht, möchten Sie Ihre Datenbankverbindung nur einmal freigeben (oder Ihren bevorzugten Typ einer anderen Ressource auswählen ...).

Oger Psalm33
quelle
1

Ein weiterer Aspekt, der oben nicht erwähnt wurde, ist die Tatsache, dass jeder Try-Catch einen gewissen Einfluss auf den Stack hat, was Auswirkungen auf rekursive Methoden haben kann.

Wenn die Methode "Outer ()" die Methode "Inner ()" aufruft (die sich möglicherweise rekursiv aufruft), versuchen Sie, den Try-Catch nach Möglichkeit in der Methode "Outer ()" zu finden. Ein einfaches Beispiel für einen "Stapelabsturz", das wir in einer Leistungsklasse verwenden, schlägt bei etwa 6.400 Frames fehl, wenn sich der Try-Catch in der inneren Methode befindet, und bei etwa 11.600 Frames, wenn er sich in der äußeren Methode befindet.

In der realen Welt kann dies ein Problem sein, wenn Sie das zusammengesetzte Muster verwenden und große, komplexe verschachtelte Strukturen haben.

Jeff Hill
quelle
0

Wenn Sie Exception für jede Iteration abfangen oder überprüfen möchten, bei welcher Iteration Exception ausgelöst wird, und alle Exceptions in einer itertaion abfangen möchten, platzieren Sie try ... catch in der Schleife. Dadurch wird die Schleife nicht unterbrochen, wenn eine Ausnahme auftritt, und Sie können jede Ausnahme in jeder Iteration in der gesamten Schleife abfangen.

Wenn Sie die Schleife unterbrechen und die Ausnahme bei jedem Auslösen untersuchen möchten, verwenden Sie try ... catch out of the loop. Dadurch wird die Schleife unterbrochen und Anweisungen nach catch (falls vorhanden) ausgeführt.

Es hängt alles von Ihren Bedürfnissen ab. Ich bevorzuge die Verwendung von try ... catch innerhalb der Schleife während der Bereitstellung, da die Ergebnisse im Falle einer Ausnahme nicht mehrdeutig sind und die Schleife nicht unterbrochen und vollständig ausgeführt wird.

Juned Khan Momin
quelle