Best Practices für die Ausnahmeverwaltung in Java oder C # [geschlossen]


117

Ich bin nicht in der Lage zu entscheiden, wie Ausnahmen in meiner Anwendung behandelt werden sollen.

Viel, wenn meine Probleme mit Ausnahmen darin bestehen, 1) über einen Remote-Dienst auf Daten zuzugreifen oder 2) ein JSON-Objekt zu deserialisieren. Leider kann ich für keine dieser Aufgaben einen Erfolg garantieren (Netzwerkverbindung trennen, fehlerhaftes JSON-Objekt, das außerhalb meiner Kontrolle liegt).

Wenn ich auf eine Ausnahme stoße, fange ich sie einfach in der Funktion ab und gebe FALSE an den Aufrufer zurück. Meine Logik ist, dass der Anrufer sich nur darum kümmert, ob die Aufgabe erfolgreich war und nicht, warum sie nicht erfolgreich war.

Hier ist ein Beispielcode (in JAVA) einer typischen Methode.

public boolean doSomething(Object p_somthingToDoOn)
{
    boolean result = false;

    try{
        // if dirty object then clean
        doactualStuffOnObject(p_jsonObject);

        //assume success (no exception thrown)
        result = true;
    }
    catch(Exception Ex)
    {
        //don't care about exceptions
        Ex.printStackTrace();
    }
    return result;
}

Ich denke, dieser Ansatz ist in Ordnung, aber ich bin wirklich neugierig, welche Best Practices für die Verwaltung von Ausnahmen gelten (sollte ich eine Ausnahme wirklich bis zum Ende eines Aufrufstapels sprudeln lassen?).

Zusammenfassend zu den wichtigsten Fragen:

  1. Ist es in Ordnung, Ausnahmen nur abzufangen, aber nicht in die Luft zu sprudeln oder das System offiziell zu benachrichtigen (entweder über ein Protokoll oder eine Benachrichtigung an den Benutzer)?
  2. Welche Best Practices gibt es für Ausnahmen, die nicht dazu führen, dass alles einen Try / Catch-Block erfordert?

Follow Up / Edit

Vielen Dank für das Feedback und einige hervorragende Quellen zum Online-Ausnahmemanagement:

Es scheint, dass das Ausnahmemanagement eines der Dinge ist, die je nach Kontext variieren. Vor allem aber sollte man konsistent sein, wie Ausnahmen innerhalb eines Systems verwaltet werden.

Achten Sie außerdem auf Code-Rot durch übermäßiges Ausprobieren oder Nicht-Respektieren einer Ausnahme (eine Ausnahme warnt das System, was muss noch gewarnt werden?).

Dies ist auch ein ziemlich guter Kommentar von m3rLinEz .

Ich stimme Anders Hejlsberg und Ihnen eher zu, dass es den meisten Anrufern nur wichtig ist, ob die Operation erfolgreich ist oder nicht.

Aus diesem Kommentar ergeben sich einige Fragen, über die beim Umgang mit Ausnahmen nachgedacht werden muss:

  • Was ist der Punkt, an dem diese Ausnahme ausgelöst wird?
  • Wie macht es Sinn, damit umzugehen?
  • Interessiert sich der Anrufer wirklich für die Ausnahme oder interessiert es ihn nur, ob der Anruf erfolgreich war?
  • Ist es sinnvoll, einen Anrufer zu zwingen, eine potenzielle Ausnahme zu verwalten?
  • Sind Sie respektvoll gegenüber den Redewendungen der Sprache?
    • Müssen Sie wirklich ein Erfolgsflag wie boolean zurückgeben? Die Rückgabe von Booleschen Werten (oder Int) ist eher eine C-Denkweise als eine Java-Denkweise (in Java würden Sie nur die Ausnahme behandeln).
    • Befolgen Sie die mit der Sprache verknüpften Fehlerverwaltungskonstrukte :)!

Obwohl der Artikel aus der Orakel-Community in Java ist, ist er ein allgemeiner Rat für eine ziemlich breite Sprachklasse. Schöner Artikel, genau das, wonach ich gesucht habe.
Bunny Rabbit

Antworten:


61

Es scheint mir seltsam, dass Sie Ausnahmen abfangen und in Fehlercodes umwandeln möchten. Warum würde der Anrufer Ihrer Meinung nach Fehlercodes Ausnahmen vorziehen, wenn letzterer sowohl in Java als auch in C # die Standardeinstellung ist?

Wie für Ihre Fragen:

  1. Sie sollten nur Ausnahmen abfangen, die Sie tatsächlich behandeln können. Nur Ausnahmen zu fangen ist in den meisten Fällen nicht das Richtige. Es gibt einige Ausnahmen (z. B. Protokollierungs- und Marshalling-Ausnahmen zwischen Threads), aber selbst in diesen Fällen sollten Sie die Ausnahmen generell erneut auslösen.
  2. Sie sollten definitiv nicht viele try / catch-Anweisungen in Ihrem Code haben. Auch hier besteht die Idee darin, nur Ausnahmen abzufangen, mit denen Sie umgehen können. Sie können einen obersten Ausnahmebehandler hinzufügen, um nicht behandelte Ausnahmen in etwas für den Endbenutzer nützliches zu verwandeln. Andernfalls sollten Sie nicht versuchen, jede einzelne Ausnahme an jedem möglichen Ort abzufangen.

Warum jemand Fehlercodes anstelle von Ausnahmen haben möchte ... Ich fand es immer seltsam, dass HTTP immer noch Fehlercodes verwendet, obwohl meine Anwendung eine Ausnahme generiert. Warum kann ich mit HTTP die Ausnahme nicht unverändert weitergeben?
Trejkaz

Das Beste, was Sie tun können, ist, Ihre Fehlercodes in eine Monade zu verpacken
Lindenrovio

@Trejkaz Sie möchten die Ausnahmedetails nicht an Benutzer zurückgeben, da dies ein Sicherheitsrisiko darstellt. Aus diesem Grund geben HTML-Server Fehlercodes zurück. Es ist auch ein Lokalisierungsproblem, eine Fehlermeldung zurückzugeben, und wahrscheinlich wird der HTML-Code größer und die Rückgabe langsamer. All dies ist der Grund, warum HTML-Server meiner Meinung nach Fehlercodes zurückgeben.
Didier A.

Ich denke, es ist besser zu sagen: "Sie sollten nur Ausnahmen unterdrücken, mit denen Sie tatsächlich umgehen können."
Didier A.

@didibus Warum sollten Sicherheitsbedenken Ihrer Meinung nach zu Unannehmlichkeiten bei der Entwicklung führen? Ich habe nie etwas über die Produktion gesagt. Bei der Lokalisierung von Fehlermeldungen ist dieses Problem bereits auf der gesamten Website aufgetreten, und die Benutzer scheinen damit fertig zu werden.
Trejkaz

25

Dies hängt von der Anwendung und der Situation ab. Wenn Sie eine Bibliothekskomponente erstellen, sollten Sie Ausnahmen in die Luft sprudeln lassen, obwohl diese so verpackt werden sollten, dass sie mit Ihrer Komponente kontextbezogen sind. Wenn Sie beispielsweise eine XML-Datenbank erstellen und beispielsweise das Dateisystem zum Speichern Ihrer Daten verwenden und zum Sichern der Daten Dateisystemberechtigungen verwenden. Sie möchten keine FileIOAccessDenied-Ausnahme auslösen, da dadurch Ihre Implementierung verloren geht. Stattdessen würden Sie die Ausnahme umbrechen und einen AccessDenied-Fehler auslösen. Dies gilt insbesondere dann, wenn Sie die Komponente an Dritte vertreiben.

Ob es in Ordnung ist, Ausnahmen zu schlucken. Das hängt von Ihrem System ab. Wenn Ihre Anwendung die Fehlerfälle behandeln kann und es keinen Vorteil hat, den Benutzer darüber zu informieren, warum sie fehlgeschlagen ist, fahren Sie fort, obwohl ich dringend empfehle, dass Sie den Fehler protokollieren. Ich fand es immer frustrierend, aufgerufen zu werden, um ein Problem zu beheben und festzustellen, dass sie die Ausnahme verschluckt haben (oder sie ersetzt und stattdessen eine neue ausgelöst haben, ohne die innere Ausnahme zu setzen).

Im Allgemeinen verwende ich die folgenden Regeln:

  1. In meinen Komponenten und Bibliotheken fange ich nur dann eine Ausnahme ab, wenn ich beabsichtige, damit umzugehen oder etwas basierend darauf zu tun. Oder wenn ich in einer Ausnahme zusätzliche Kontextinformationen bereitstellen möchte.
  2. Ich verwende einen allgemeinen Try-Catch am Einstiegspunkt der Anwendung oder auf der höchstmöglichen Ebene. Wenn eine Ausnahme auftritt, protokolliere ich sie einfach und lasse sie fehlschlagen. Im Idealfall sollten Ausnahmen niemals hierher kommen.

Ich finde den folgenden Code ein Geruch:

try
{
    //do something
}
catch(Exception)
{
   throw;
}

Code wie dieser hat keinen Sinn und sollte nicht enthalten sein.


@ Josh, guter Punkt zum Schlucken von Ausnahmen, aber ich glaube, es gibt nur wenige Fälle, in denen es akzeptabel ist, einfach Ausnahmen zu schlucken. Im letzten Projekt wurde Ihr Code-Snippet beauftragt, es stank. Wenn Sie die Ausnahme nicht behandeln können, versuchen Sie, sie nicht zu schlucken.
Smaclell

Wie ich bereits sagte, hängt dies alles von der App und dem spezifischen Kontext ab. Es gibt Zeiten, in denen ich Ausnahmen schlucke, obwohl dies selten ist, und ich kann mich nicht an das letzte Mal erinnern, als ich es getan habe ;-) Es war wahrscheinlich, als ich meinen eigenen Logger schrieb und das Schreiben in das Protokoll und das sekundäre Protokoll fehlschlugen.
JoshBerke

Der Code dient einem Punkt: Sie können einen Haltepunkt beim "Wurf" setzen.
Rauhotz

3
Schwachpunkt: Sie können VS anweisen, bei einer ausgelösten Ausnahme zu brechen, oder Sie können sie eingrenzen und eine bestimmte Ausnahme auswählen. In VS2008 gibt es einen Menüpunkt unter Debug (Sie müssen Ihre Symbolleisten anpassen, um ihn zu finden) Aufgerufene Ausnahmen
JoshBerke

Das Beispiel "Codegeruch" hat selbst in dieser einfachen Form einen eindeutigen Nebeneffekt. Wenn // do somethingirgendwelche enthält try/finallyBlöcke , die um den Punkt führt, die finallywerden Blöcke vor dem Ausführen catchBlock. Ohne das try/catchfliegt die Ausnahme bis zum oberen Rand des Stapels, ohne dass finallyBlöcke ausgeführt werden. Auf diese Weise kann der Handler der obersten Ebene entscheiden, ob die finallyBlöcke ausgeführt werden sollen oder nicht .
Daniel Earwicker

9

Ich möchte eine weitere gute Quelle zu diesem Thema empfehlen. Es ist ein Interview mit den Erfindern von C # und Java, Anders Hejlsberg und James Gosling, zum Thema Javas Checked Exception.

Fehler und Ausnahmen

Es gibt auch großartige Ressourcen am Ende der Seite.

Ich stimme Anders Hejlsberg und Ihnen eher zu, dass es den meisten Anrufern nur wichtig ist, ob die Operation erfolgreich ist oder nicht.

Bill Venners : Sie haben Bedenken hinsichtlich Skalierbarkeit und Versionierung in Bezug auf geprüfte Ausnahmen erwähnt. Können Sie klarstellen, was Sie mit diesen beiden Themen meinen?

Anders Hejlsberg : Beginnen wir mit der Versionierung, da die Probleme dort ziemlich leicht zu erkennen sind. Angenommen, ich erstelle eine Methode foo, die deklariert, dass sie die Ausnahmen A, B und C auslöst. In Version zwei von foo möchte ich eine Reihe von Funktionen hinzufügen, und jetzt könnte foo die Ausnahme D auslösen. Dies ist eine wichtige Änderung für mich Fügen Sie D zur Throws-Klausel dieser Methode hinzu, da der vorhandene Aufrufer dieser Methode diese Ausnahme mit ziemlicher Sicherheit nicht behandelt.

Das Hinzufügen einer neuen Ausnahme zu einer Throws-Klausel in einer neuen Version unterbricht den Client-Code. Es ist wie das Hinzufügen einer Methode zu einer Schnittstelle. Nachdem Sie eine Schnittstelle veröffentlicht haben, ist sie für alle praktischen Zwecke unveränderlich, da jede Implementierung möglicherweise über die Methoden verfügt, die Sie in der nächsten Version hinzufügen möchten. Sie müssen stattdessen eine neue Benutzeroberfläche erstellen. In ähnlicher Weise müssten Sie mit Ausnahmen entweder eine ganz neue Methode namens foo2 erstellen, die mehr Ausnahmen auslöst, oder Sie müssten die Ausnahme D im neuen foo abfangen und das D in ein A, B oder C umwandeln.

Bill Venners : Aber brechen Sie in diesem Fall nicht trotzdem ihren Code, selbst in einer Sprache ohne geprüfte Ausnahmen? Wenn die neue Version von foo eine neue Ausnahme auslöst, über die Clients nachdenken sollten, ist ihr Code dann nicht nur dadurch beschädigt, dass sie diese Ausnahme beim Schreiben des Codes nicht erwartet haben?

Anders Hejlsberg : Nein, weil es den Menschen in vielen Fällen egal ist. Sie werden keine dieser Ausnahmen behandeln. Es gibt einen Ausnahmebehandler der untersten Ebene um ihre Nachrichtenschleife. Dieser Handler wird nur einen Dialog aufrufen, der besagt, was schief gelaufen ist, und fortfahren. Die Programmierer schützen ihren Code, indem sie versuchen, endlich überall zu schreiben, damit sie korrekt zurücktreten, wenn eine Ausnahme auftritt, aber sie sind nicht wirklich daran interessiert, die Ausnahmen zu behandeln.

Die Throws-Klausel, zumindest die Art und Weise, wie sie in Java implementiert ist, zwingt Sie nicht unbedingt dazu, die Ausnahmen zu behandeln. Wenn Sie sie jedoch nicht behandeln, müssen Sie genau erkennen, welche Ausnahmen möglicherweise durchlaufen werden. Sie müssen entweder deklarierte Ausnahmen abfangen oder sie in Ihre eigene Throws-Klausel einfügen. Um diese Anforderung zu umgehen, machen die Leute lächerliche Dinge. Zum Beispiel dekorieren sie jede Methode mit "löst eine Ausnahme aus". Das macht die Funktion einfach komplett zunichte und Sie haben den Programmierer dazu gebracht, mehr verschlungenes Zeug zu schreiben. Das hilft niemandem.

BEARBEITEN: Weitere Details zur Konvertierung hinzugefügt


Danke dafür! Ich habe meine Frage mit Informationen zu Ihrer Antwort aktualisiert!
AtariPete

Es hört sich so an, als ob Mr. Hejlsberg die Behandlung von Pokemon-Ausnahmen rechtfertigt. Eines der großen Probleme beim Entwurf von Ausnahmen in Java und C # besteht darin, dass zu viele Informationen im Typ einer Ausnahme codiert werden , während Informationen in Ausnahmefällen gespeichert werden sollten, die nicht konsistent verfügbar sind. Ausnahmen sollten sich auf dem Aufrufstapel ausbreiten, bis alle dadurch dargestellten abnormalen Bedingungen behoben sind. Leider gibt die Art einer Ausnahme - selbst wenn sie erkannt wird - wenig Aufschluss darüber, ob eine Situation gelöst ist. Wenn eine Ausnahme nicht erkannt wird ...
Supercat

... ist die Situation noch schlimmer. Wenn Code aufruft FetchDataund eine Ausnahme eines unerwarteten Typs auslöst, kann er nicht wissen, ob diese Ausnahme lediglich bedeutet, dass die Daten nicht verfügbar sind (in diesem Fall würde die Fähigkeit des Codes, ohne sie auszukommen, sie "auflösen"), oder ob dies bedeutet, dass die CPU in Flammen steht und das System bei der ersten Gelegenheit eine "Sicherheitsabschaltung" durchführen sollte. Es hört sich so an, als würde Herr Hejlsberg vorschlagen, dass der Code den ersteren annehmen sollte; Vielleicht ist das angesichts der bestehenden Ausnahmehierarchien die bestmögliche Strategie, aber es scheint trotzdem schwierig zu sein.
Supercat

Ich bin damit einverstanden, dass Würfe Exceptin lächerlich sind, da fast alles eine Ausnahme auslösen kann. Sie sollten einfach davon ausgehen, dass dies passieren kann. Wenn Sie jedoch Ausnahmen wie die Würfe A, B, C angeben, handelt es sich nur um eine Anmerkung. Für mich sollte sie wie ein Kommentarblock verwendet werden. Es ist wie zu sagen, hey Client meiner Funktion, hier ist ein Tipp, vielleicht möchten Sie sich mit A, B, C befassen, weil diese Fehler wahrscheinlich auftreten, wenn Sie mich verwenden. Wenn Sie in Zukunft D hinzufügen, ist es keine große Sache, wenn es nicht behandelt wird, aber es ist wie das Hinzufügen einer neuen Dokumentation. Übrigens, jetzt wäre es auch nützlich, D.
Didier A.

8

Überprüfte Ausnahmen sind ein kontroverses Thema im Allgemeinen und in Java im Besonderen (später werde ich versuchen, einige Beispiele für diejenigen zu finden, die dafür und dagegen sind).

Als Faustregeln sollte die Ausnahmebehandlung in keiner bestimmten Reihenfolge um diese Richtlinien herumgehen:

  • Protokollieren Sie aus Gründen der Wartbarkeit immer Ausnahmen, damit das Protokoll Sie auf den Ort hinweist, an dem Ihr Fehler wahrscheinlich begonnen hat, wenn Sie Fehler sehen. Niemals verlassen printStackTrace()oder ähnliches, es besteht die Möglichkeit, dass einer Ihrer Benutzer irgendwann eine dieser Stapelspuren erhält und genau keine Kenntnisse darüber hat, was er damit tun soll.
  • Fangen Sie Ausnahmen ab, die Sie behandeln können, und nur diese, und behandeln Sie sie , werfen Sie sie nicht einfach auf den Stapel.
  • Fangen Sie immer eine bestimmte Ausnahmeklasse ab, und im Allgemeinen sollten Sie niemals den Typ abfangen. Es Exceptionist sehr wahrscheinlich, dass Sie ansonsten wichtige Ausnahmen verschlucken.
  • Niemals (jemals) Errors fangen !! , was bedeutet: Fange niemals Throwables, da Errors Unterklassen der letzteren sind. Errors sind Probleme, die Sie höchstwahrscheinlich nie lösen können (z. B. OutOfMemoryoder andere JVM-Probleme).

Stellen Sie in Bezug auf Ihren speziellen Fall sicher, dass jeder Client, der Ihre Methode aufruft, den richtigen Rückgabewert erhält. Wenn etwas fehlschlägt, gibt eine boolesche Rückgabemethode möglicherweise false zurück. Stellen Sie jedoch sicher, dass die Stellen, an denen Sie diese Methode aufrufen, damit umgehen können.


Überprüfte Ausnahmen sind in C # kein Problem, da sie nicht vorhanden sind.
Cletus

3
Imho, manchmal ist es gut, Fehler zu erkennen: Ich erinnere mich an eine sehr speicherintensive Java-App, die ich geschrieben habe. Ich habe das OutOfMemory-Ex abgefangen und dem Benutzer eine Nachricht angezeigt, dass er nicht genügend Speicher hat, dass er andere Programme beenden soll, und ihm gesagt, wie er das JVM mit mehr zugewiesenem Heap-Speicherplatz starten soll. Ich denke es hat geholfen.
Lena Schimmel

5

Sie sollten nur die Ausnahmen abfangen, mit denen Sie umgehen können. Wenn Sie beispielsweise über ein Netzwerk lesen und die Verbindung abläuft und eine Ausnahme auftritt, können Sie es erneut versuchen. Wenn Sie jedoch über ein Netzwerk lesen und eine IndexOutOfBounds-Ausnahme erhalten, können Sie damit wirklich nicht umgehen, da Sie nicht wissen, was die Ursache ist. Wenn Sie false oder -1 oder null zurückgeben, stellen Sie sicher, dass es sich um bestimmte Ausnahmen handelt. Ich möchte nicht, dass eine Bibliothek, die ich verwende, in einem Netzwerk einen Lesevorgang zurückgibt, wenn die Ausnahme darin besteht, dass der Heap nicht über genügend Speicher verfügt.


3

Ausnahmen sind Fehler, die nicht Teil der normalen Programmausführung sind. Abhängig davon, was Ihr Programm tut und wie es verwendet wird (dh ein Textverarbeitungsprogramm oder ein Herzmonitor), möchten Sie verschiedene Dinge tun, wenn Sie auf eine Ausnahme stoßen. Ich habe mit Code gearbeitet, der Ausnahmen als Teil der normalen Ausführung verwendet, und es ist definitiv ein Codegeruch.

Ex.

try
{
   sendMessage();

   if(message == success)
   {
       doStuff();
   }
   else if(message == failed)
   {
       throw;
   }
}
catch(Exception)
{
    logAndRecover();
}

Dieser Code macht mich barf. IMO sollten Sie keine Ausnahmen wiederherstellen, es sei denn, es ist ein kritisches Programm. Wenn Sie Ausnahmen werfen, passieren schlimme Dinge.


2

All dies scheint vernünftig zu sein, und häufig hat Ihr Arbeitsplatz möglicherweise eine Richtlinie. Bei uns haben wir Ausnahmetypen definiert: SystemException(nicht markiert) und ApplicationException(aktiviert).

Wir haben uns darauf geeinigt, dass SystemExceptiones unwahrscheinlich ist, dass s wiederhergestellt werden können, und dass sie einmal an der Spitze behandelt werden. Zur weiteren Zusammenhang auch unsere SystemExceptionsind s exteneded um anzuzeigen , wo sie aufgetreten ist , zB RepositoryException, ServiceEceptionusw.

ApplicationExceptions könnte eine geschäftliche Bedeutung haben InsufficientFundsExceptionund sollte vom Client-Code behandelt werden.

Ohne ein konkretes Beispiel ist es schwierig, Ihre Implementierung zu kommentieren, aber ich würde niemals Rückkehrcodes verwenden, sie sind ein Wartungsproblem. Sie können eine Ausnahme verschlucken, müssen jedoch entscheiden, warum und das Ereignis und die Stapelverfolgung immer protokollieren. Da Ihre Methode keine andere Verarbeitung hat, ist sie ziemlich redundant (außer für die Kapselung?) Und doactualStuffOnObject(p_jsonObject);könnte daher einen Booleschen Wert zurückgeben!


1

Nach einigem Nachdenken und Betrachten Ihres Codes scheint es mir, dass Sie die Ausnahme einfach als Booleschen Wert erneut auslösen. Sie können die Methode diese Ausnahme einfach durchlaufen lassen (Sie müssen sie nicht einmal abfangen) und sie im Aufrufer behandeln, da dies der Ort ist, an dem es darauf ankommt. Wenn die Ausnahme den Aufrufer veranlasst, diese Funktion erneut zu versuchen, sollte der Anrufer derjenige sein, der die Ausnahme abfängt.

Es kann vorkommen, dass die Ausnahme, auf die Sie stoßen, für den Anrufer keinen Sinn ergibt (dh es handelt sich um eine Netzwerkausnahme). In diesem Fall sollten Sie sie in eine domänenspezifische Ausnahme einschließen.

Wenn andererseits die Ausnahme einen nicht behebbaren Fehler in Ihrem Programm signalisiert (dh das endgültige Ergebnis dieser Ausnahme ist die Programmbeendigung), möchte ich dies persönlich explizit machen, indem ich sie abfange und eine Laufzeitausnahme auslöse.


1

Wenn Sie das Codemuster in Ihrem Beispiel verwenden möchten, nennen Sie es TryDoSomething und fangen Sie nur bestimmte Ausnahmen ab.

Erwägen Sie auch die Verwendung eines Ausnahmefilters, wenn Sie Ausnahmen für Diagnosezwecke protokollieren. VB bietet Sprachunterstützung für Ausnahmefilter. Der Link zu Greggms Blog enthält eine Implementierung, die von C # aus verwendet werden kann. Ausnahmefilter haben bessere Eigenschaften für die Debugbarkeit gegenüber Catch und Rethrow. Insbesondere können Sie das Problem im Filter protokollieren und die Ausnahme weiter verbreiten lassen. Mit dieser Methode kann ein JIT-Debugger (Just in Time) den vollständigen Originalstapel anhängen. Ein erneuter Wurf schneidet den Stapel an der Stelle ab, an der er erneut geworfen wurde.

Die Fälle, in denen TryXXXX sinnvoll ist, sind, wenn Sie eine Drittanbieterfunktion einschließen, die Fälle auslöst, die nicht wirklich außergewöhnlich sind oder einfach nur schwer zu testen sind, ohne die Funktion aufzurufen. Ein Beispiel wäre so etwas wie:

// throws NumberNotHexidecimalException
int ParseHexidecimal(string numberToParse); 

bool TryParseHexidecimal(string numberToParse, out int parsedInt)
{
     try
     {
         parsedInt = ParseHexidecimal(numberToParse);
         return true;
     }
     catch(NumberNotHexidecimalException ex)
     {
         parsedInt = 0;
         return false;
     }
     catch(Exception ex)
     {
         // Implement the error policy for unexpected exceptions:
         // log a callstack, assert if a debugger is attached etc.
         LogRetailAssert(ex);
         // rethrow the exception
         // The downside is that a JIT debugger will have the next
         // line as the place that threw the exception, rather than
         // the original location further down the stack.
         throw;
         // A better practice is to use an exception filter here.
         // see the link to Exception Filter Inject above
         // http://code.msdn.microsoft.com/ExceptionFilterInjct
     }
}

Ob Sie ein Muster wie TryXXX verwenden oder nicht, ist eher eine Stilfrage. Die Frage, alle Ausnahmen zu fangen und zu schlucken, ist kein Stilproblem. Stellen Sie sicher, dass sich unerwartete Ausnahmen verbreiten dürfen!


Ich liebe das TryXXX-Muster in .net.
JoshBerke

1

Ich schlage vor, Ihre Hinweise aus der Standardbibliothek für die von Ihnen verwendete Sprache zu übernehmen. Ich kann nicht für C # sprechen, aber schauen wir uns Java an.

Zum Beispiel hat java.lang.reflect.Array eine statische setMethode:

static void set(Object array, int index, Object value);

Der C-Weg wäre

static int set(Object array, int index, Object value);

... wobei der Rückgabewert ein Erfolgsindikator ist. Aber du bist nicht mehr in der C-Welt.

Sobald Sie Ausnahmen akzeptieren, sollten Sie feststellen, dass dies Ihren Code einfacher und klarer macht, indem Sie Ihren Fehlerbehandlungscode von Ihrer Kernlogik entfernen. Ziel ist es, viele Anweisungen in einem einzigen tryBlock zu haben.

Wie andere angemerkt haben, sollten Sie in der Art der Ausnahme, die Sie fangen, so genau wie möglich sein.


Dies ist ein sehr gültiger Kommentar. Seien Sie respektvoll gegenüber der Sprache und wie sie traditionell mit solchen Problemen umgeht. Bringen Sie keine C-Denkweise in eine Java-Welt.
AtariPete

0

Wenn Sie eine Ausnahme abfangen und false zurückgeben, sollte dies eine sehr spezifische Ausnahme sein. Du machst das nicht, du fängst sie alle und gibst falsch zurück. Wenn ich eine MyCarIsOnFireException bekomme, möchte ich sofort davon erfahren! Die restlichen Ausnahmen interessieren mich vielleicht nicht. Sie sollten also einen Stapel von Ausnahmebehandlungsroutinen haben, die für einige Ausnahmen "whoa whoa, hier stimmt etwas nicht" sagen (erneut werfen oder eine neue Ausnahme abfangen und erneut werfen, die besser erklärt, was passiert ist) und für andere einfach false zurückgeben.

Wenn dies ein Produkt ist, das Sie starten werden, sollten Sie diese Ausnahmen irgendwo protokollieren, damit Sie die Dinge in Zukunft optimieren können.

Bearbeiten: Was die Frage betrifft, alles in einen Versuch / Fang zu packen, denke ich, dass die Antwort ja ist. Ausnahmen sollten in Ihrem Code so selten sein, dass der Code im catch-Block so selten ausgeführt wird, dass er die Leistung überhaupt nicht beeinträchtigt. Eine Ausnahme sollte ein Zustand sein, in dem Ihre Zustandsmaschine kaputt gegangen ist und nicht weiß, was zu tun ist. Zumindest eine Ausnahme erneut auslösen, die erklärt, was zu der Zeit geschah, und die gefangene Ausnahme enthält. "Ausnahme in der Methode doSomeStuff ()" ist nicht sehr hilfreich für alle, die herausfinden müssen, warum es im Urlaub (oder bei einem neuen Job) kaputt gegangen ist.


Vergessen Sie nicht, dass das Einrichten eines Ausnahmeblocks auch kostet ...
devstuff

0

Meine Strategie:

Wenn die ursprüngliche Funktion void zurückgibt, ändere ich sie in bool . Wenn eine Ausnahme / ein Fehler aufgetreten ist, geben Sie false zurück . Wenn alles in Ordnung war, geben Sie true zurück .

Wenn die Funktion etwas zurückgeben soll, geben Sie bei Auftreten einer Ausnahme / eines Fehlers null zurück , andernfalls das zurückgegebene Element.

Anstatt einen String zu boolen zurückgegeben werden, die die Beschreibung des Fehlers enthält.

In jedem Fall protokollieren Sie den Fehler, bevor Sie etwas zurückgeben.


0

Einige ausgezeichnete Antworten hier. Ich möchte hinzufügen, dass, wenn Sie am Ende etwas haben, das Sie gepostet haben, zumindest mehr als die Stapelverfolgung gedruckt werden. Sagen Sie, was Sie zu der Zeit getan haben, und Ex.getMessage (), um dem Entwickler eine Chance zum Kampf zu geben.


Ich stimme vollkommen zu. Ich habe nur Ex.printStackTrace () gemacht; als Beispiel für etwas, das ich im Fang gemacht habe (dh nicht neu geworfen).
AtariPete

0

Try / Catch-Blöcke bilden einen zweiten Satz von Logik, der über den ersten (Haupt-) Satz eingebettet ist. Als solche sind sie eine großartige Möglichkeit, unlesbaren, schwer zu debuggenden Spaghetti-Code zu entfernen.

Vernünftigerweise wirken sie bei der Lesbarkeit Wunder, aber Sie sollten nur zwei einfache Regeln befolgen:

  • Verwenden Sie sie (sparsam) auf niedriger Ebene, um Probleme bei der Bibliotheksbehandlung zu erkennen und sie wieder in den logischen Hauptfluss zu streamen. Der größte Teil der von uns gewünschten Fehlerbehandlung sollte aus dem Code selbst als Teil der Daten selbst stammen. Warum besondere Bedingungen stellen, wenn die zurückgegebenen Daten keine besonderen sind?

  • Verwenden Sie einen großen Handler auf der höheren Ebene, um einige oder alle seltsamen Bedingungen im Code zu verwalten, die nicht auf einer niedrigeren Ebene abgefangen werden. Machen Sie etwas Nützliches mit den Fehlern (Protokolle, Neustarts, Wiederherstellungen usw.).

Abgesehen von diesen beiden Arten der Fehlerbehandlung sollte der gesamte Rest des Codes in der Mitte frei und frei von Try / Catch-Code und Fehlerobjekten sein. Auf diese Weise funktioniert es einfach und wie erwartet, egal wo Sie es verwenden oder was Sie damit machen.

Paul.


0

Ich bin vielleicht etwas spät dran mit der Antwort, aber die Fehlerbehandlung können wir immer ändern und im Laufe der Zeit weiterentwickeln. Wenn Sie mehr über dieses Thema lesen möchten, habe ich in meinem neuen Blog einen Beitrag darüber geschrieben. http://taoofdevelopment.wordpress.com

Viel Spaß beim Codieren.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.