Verwenden Sie "Ausnahmen fangen", um die Lesbarkeit zu verbessern, gut oder schlecht?

9

In dem Abschnitt Wann sollte eine Ausnahme in The Pragmatic Programmer verwendet werden , schreibt das Buch Folgendes anstelle von:

retcode = OK;
     if (socket.read(name) != OK) {
      retcode = BAD_READ;
    }
     else {
      processName(name);
       if (socket.read(address) != OK) {
        retcode = BAD_READ;
      }
       else {
        processAddress(address);
         if (socket.read(telNo) != OK) {
          retcode = BAD_READ;
        }
         else {
          //  etc, etc...
        }
      }
    }
     return retcode;

, Sie bevorzugen:

 retcode = OK;
     try {
      socket.read(name);
      process(name);
      socket.read(address);
      processAddress(address);
      socket.read(telNo);
      //  etc, etc...
    }
     catch (IOException e) {
      retcode = BAD_READ;
      Logger.log( "Error reading individual: " + e.getMessage());
    }
     return retcode;

einfach weil es ordentlicher aussieht. Ich bin alles für saubereren Code, aber ist das unnötige Auffinden von Ausnahmen nicht ein Leistungsengpass?

Ich kann verstehen, dass wir die winzige Optimierung für saubereren Code aufgeben sollten (mindestens 99% der Fälle), aber soweit ich weiß, gehören Ausnahmen zur Codeklasse, die eine merkliche Verzögerung in der Laufzeit haben. Daher habe ich mich gefragt, was die Rechtfertigung dafür ist, dass der zweite Code dem ersten Code vorgezogen wird.

Oder eher, welchen Code würden Sie bevorzugen?

Pacerier
quelle
migriert von Code Review, weil es eine Best-Practice-Frage ist, keine Code-Review-Frage
Winston Ewert
1
IMO, wenn Sie erwarten , diese Werte aus dem Socket lesen zu können, ist ein IOEx eine Ausnahme.
Steven Evers
Relevant für diese Diskussion: Verwenden von Throwable für andere Dinge als Ausnahmen
Daniel R Hicks
Hast du gemessen?
@ ThorbjørnRavnAndersen natürlich habe ich das Buch gelesen und habe keinen wirklichen "Testfall" zum Messen. Aber wenn wir es in einem erfundenen Code messen, dann gibt es offensichtlich eine Leistungsstrafe
Pacerier

Antworten:

18

Ausnahmen sind normalerweise nur langsamer, wenn sie tatsächlich ausgelöst werden. Normalerweise sind die Ausnahmen in solchen Situationen selten, daher sollten Sie sich keine Sorgen machen. Sie sollten sich nur dann wirklich um die Leistung von Ausnahmen sorgen, wenn diese ständig auftreten und daher ein wichtiger Faktor sind.

Der zweite Code ist besser, weil es viel einfacher ist, der Logik zu folgen. Die Fehlerbehandlung ist gut lokalisiert. Der einzige Einwand ist, dass Sie Ausnahmen verwenden, wenn Sie Ausnahmen verwenden. Fangen Sie die Ausnahmen nicht ab und geben Sie dann einen Fehlercode zurück.

Winston Ewert
quelle
4
Einverstanden, ich hasse es, Fehlercodes in einer Sprache zu sehen, die Ausnahmen hat. Die meiste Zeit sollten Sie fangen, protokollieren und erneut werfen, ohne den Aufrufstapel zu beschädigen . Und meistens spielt es keine Rolle, ob ein "Ausnahmefall" langsamer ist. Die App hat ein Problem. Nehmen Sie sich Zeit, um es richtig zu behandeln. Solange die Ausnahme außergewöhnlich ist und nicht Teil des normalen Betriebs oder des glücklichen Pfads der Anwendung ist, handelt es sich normalerweise nicht um einen Codegeruch.
CaffGeek
Übrigens habe ich mich gefragt, wie wir die EOFException rechtfertigen können, mit der DataStreams ein Zeilenende erkennt (Zeilenende ist nicht außergewöhnlich, wie es in docs.oracle.com/javase/tutorial/essential/io/datastreams.html gezeigt wird) ?
Pacerier
@ Pacerier, es könnte außergewöhnlich sein. Wenn die Eingabe in der Zeile nicht mehr ausreicht, kann dies auf schlechte Daten oder einen schrecklichen Fehler hinweisen. Ich vermute, dass die beabsichtigte Verwendung darin besteht, mehrere Felder aus einer Zeile heraus zu analysieren.
Winston Ewert
@Downvoter, wenn Sie ein Problem mit der Antwort haben, erklären Sie bitte!
Winston Ewert
5

Nun, wie sie auch sagen, sollten Ausnahmen die Ausnahmefälle behandeln , und da dies ein Ausnahmefall ist (dh etwas, das nur selten vorkommt), würde ich sagen, dass dies auch hier gilt.

Außerdem würde ich raten , gegen Mikro-Optimierung Dinge wie diese. Konzentrieren Sie sich mehr auf die Lesbarkeit des Codes , da Sie viel mehr Zeit mit dem Lesen von Code verbringen als mit dem Schreiben von neuem Code.

Um wirklich sicherzustellen, dass dies ein Leistungsengpass ist, führen Sie eine Profilerstellung durch und analysieren und konzentrieren Sie sich auf die kritischeren Aufgaben, die auf dieser Analyse basieren.

Andreas Johansson
quelle
5

Ich kann verstehen, dass wir die winzige Optimierung für saubereren Code aufgeben sollten (mindestens 99% der Fälle), aber soweit ich weiß, gehören Ausnahmen zur Codeklasse, die eine merkliche Verzögerung in der Laufzeit haben.

Woher weißt du das? Wie definieren Sie "spürbare Verzögerung"?

Dies ist genau die Art von vage (und völlig falscher) Leistungsmythos, die zu nutzlosen vorzeitigen Optimierungen führt.

Das Auslösen und Abfangen einer Ausnahme mag im Vergleich zum Hinzufügen von zwei Zahlen langsam sein, ist jedoch im Vergleich zum Lesen von Daten aus einem Socket völlig unbedeutend . Sie könnten wahrscheinlich tausend Ausnahmen auslösen und abfangen, während Sie ein einzelnes Netzwerkpaket gelesen haben. Und wir sprechen hier nicht von Tausenden von Ausnahmen, sondern nur von einer einzigen.

Michael Borgwardt
quelle
Ich komme aus .NET, also entschuldigen Sie meine Java-Kenntnisse, aber ich habe persönlich erlebt, dass Ausnahmen in .NET zu wahnsinnigen Verzögerungen (Sekunden) geführt haben, die durch Entfernen des "Catching-Exception-Codes"
behoben wurden
@ Pacerier, im Ernst? Größe der Sekunden? Ich denke, vielleicht hat es viele Ausnahmen gegeben? Dann konnte ich das sehen.
Winston Ewert
3
@Pacerier: Wenn Ausnahmen wahnsinnige Verzögerungen verursachen, ist die Ursache eindeutig keine Ausnahme und sollte daher auf andere Weise behandelt werden. Kein System sollte Sekunden brauchen, um eine Ausnahme zu verarbeiten, und ich denke, Microsoft ist ausreichend kompetent, um dies zu vermeiden.
David Thornley
5

Ich stimme den Antworten zu, die Sie bereits erhalten haben, dass dies ein Ausnahmefall ist. Daher ist es sinnvoll, die Ausnahmebehandlung zu verwenden.

Wenn Sie Ihre Leistungsprobleme direkter ansprechen, müssen Sie meiner Meinung nach ein Gespür für Skalierbarkeit haben. Das Auslösen / Abfangen einer Ausnahme unter diesen Umständen dauert wahrscheinlich eine Mikrosekunde. Die Flusskontrolle ist langsam - um ein Vielfaches langsamer als normale ifAussagen, keine Frage.

Denken Sie gleichzeitig daran, dass Sie hier Daten aus einem Netzwerk lesen. Mit 10 Megabit pro Sekunde (langsam für ein lokales Netzwerk, aber ziemlich schnell für Internetverbindungen) entspricht dies der Zeit zum Lesen eines Bytes an Informationen.

Natürlich entsteht dieser Overhead nur, wenn Sie die Ausnahme auch tatsächlich auslösen - wenn er nicht ausgelöst wird, gibt es normalerweise wenig oder gar keinen Overhead (zumindest nach dem, was ich gesehen habe, ist der bedeutendste Overhead nicht von der Ausnahmebehandlung selbst, da mehr potenzielle Kontrollflüsse hinzugefügt werden, was es für den Compiler schwieriger macht, den Code ebenfalls zu optimieren.

In diesem Fall schreiben Sie beim Auslösen einer Ausnahme Daten in das Protokoll. Angesichts der Art der Protokollierung stehen die Chancen gut, dass Sie diese Ausgabe löschen, sobald Sie sie schreiben (um sicherzustellen, dass sie nicht verloren geht). Das Schreiben auf die Festplatte ist (wieder) ein ziemlich langsamer Vorgang - Sie benötigen eine ziemlich schnelle SSD der Enterprise-Klasse, um sogar in den Bereich von Zehntausenden von IOPs / Sekunde zu gelangen. Eine für die Protokollierung verwendete Festplatte kann leicht auf Hunderte von IOPs / Sekunde beschränkt sein.

Fazit: es gibt Fälle , in denen Ausnahmekopf Handhabung kann erheblich sein, aber das ist fast sicher nicht einer von ihnen.

Jerry Sarg
quelle