206 Stimmen

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

Ich habe eine Schleife, die in etwa 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 es ist, das Array von Floats zurückzugeben. Ich möchte, dass diese Methode zurückgibt null wenn ein Fehler auftritt, also habe ich die Schleife in eine try...catch Block, etwa so:

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 habe ich auch daran gedacht, die try...catch Block innerhalb der Schleife, etwa so:

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 irgendeinen Grund, der dafür spricht, das eine dem anderen vorzuziehen, sei es aus Leistungsgründen oder aus anderen Gründen?


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

2 Stimmen

Ich weiß nicht, wie es um die Leistung bestellt ist, aber der Code sieht mit dem Try-Catch außerhalb der for-Schleife sauberer aus.

1voto

wnoise Punkte 9530

Der Sinn von Ausnahmen ist es, den ersten Stil zu fördern: die Fehlerbehandlung wird konsolidiert und einmalig behandelt, nicht sofort an jeder möglichen Fehlerstelle.

0 Stimmen

Falsch! Der Sinn von Ausnahmen ist es, zu bestimmen, welches außergewöhnliche Verhalten beim Auftreten eines "Fehlers" an den Tag gelegt werden soll. Die Entscheidung für einen inneren oder äußeren try/catch-Block hängt also davon ab, wie Sie die Schleifenbehandlung handhaben wollen.

0 Stimmen

Das kann ebenso gut mit Fehlerbehandlungen vor Ausnahmen geschehen, wie z.B. die Weitergabe von "error occurred"-Flags.

1voto

Stephen Wrighton Punkte 34868

Wenn es innerhalb ist, dann erhalten Sie den Overhead der Try/Catch-Struktur N-mal, im Gegensatz zu nur der einmal auf der Außenseite.


Jedes Mal, wenn eine Try/Catch-Struktur aufgerufen wird, erhöht sich der Aufwand für die Ausführung der Methode. Nur das bisschen Speicher und die Prozessor-Ticks, die für die Bearbeitung der Struktur benötigt werden. Wenn Sie eine Schleife 100 Mal ausführen, und nehmen wir an, die Kosten betragen 1 Tick pro Try/Catch-Aufruf, dann kostet es Sie 100 Ticks, wenn sich die Try/Catch-Struktur innerhalb der Schleife befindet, im Gegensatz zu nur 1 Tick, wenn sie sich außerhalb der Schleife befindet.

0 Stimmen

Können Sie den Overhead ein wenig näher erläutern?

1 Stimmen

Okay, aber Jeffrey L. Whitledge sagt, es gäbe keine zusätzliche Gemeinkosten. Können Sie eine Quelle nennen, die dies bestätigt?

0 Stimmen

Die Kosten sind gering, fast vernachlässigbar, aber sie sind da - alles hat seinen Preis. Hier ist ein Blog-Artikel von Programmer's Heaven ( tiny.cc/ZBX1b ) über .NET und hier ein Newsgroup-Post von Reshat Sabiq über JAVA ( tiny.cc/BV2hS )

1voto

Kyle Dyer Punkte 308

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

Bedenken Sie:

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

In der Zeit der Not werden Sie eine Ausnahme wie diese mit so vielen Informationen wie möglich sehr zu schätzen wissen.

0 Stimmen

Ja, auch das ist ein berechtigtes Argument. In meinem Fall lese ich aus einer Datei, so dass alles, was ich wirklich brauche, ist die Zeichenfolge, die nicht geparst werden konnte. Also habe ich System.out.println(ex) anstatt eine weitere Ausnahme zu werfen (ich möchte so viel von der Datei analysieren, wie es möglich ist).

1voto

Arne Burmeister Punkte 19217

Das hängt von der Fehlerbehandlung ab. Wenn Sie nur die Fehlerelemente auslassen wollen, versuchen Sie es mit inside:

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 lesbarer, er ist sauberer. Vielleicht wäre es besser, eine IllegalArgumentException im Fehlerfall zu werfen, anstatt null zurückzugeben.

1voto

Ogre Psalm33 Punkte 20356

Manchmal muss man später im Code ein "finally" hinzufügen (denn wer schreibt seinen Code schon beim ersten Mal perfekt?). In diesen Fällen macht es plötzlich mehr Sinn, die try/catch außerhalb der Schleife zu haben. Zum Beispiel:

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 ob ein Fehler auftritt oder nicht, Sie wollen Ihre Datenbankverbindung (oder eine andere Ressource Ihrer Wahl...) nur einmal freigeben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X