In hochrangigen Sachen Ausnahmen; in Low-Level-Sachen, Fehlercodes.
Das Standardverhalten einer Ausnahme besteht darin, den Stapel abzuwickeln und das Programm zu stoppen. Wenn ich ein Skript schreibe und einen Schlüssel suche, der nicht in einem Wörterbuch enthalten ist, ist dies wahrscheinlich ein Fehler, und ich möchte, dass das Programm angehalten wird und mich lässt weiß alles darüber.
Wenn ich jedoch einen Code schreibe , dessen Verhalten ich in jeder möglichen Situation kennen muss, möchte ich Fehlercodes. Ansonsten muss ich jede Ausnahme kennen, die von jeder Zeile in meiner Funktion ausgelöst werden kann, um zu wissen, was sie tun wird (Lesen Sie die Ausnahme, die eine Fluggesellschaft geerdet hat , um eine Vorstellung davon zu bekommen, wie schwierig dies ist). Es ist mühsam und schwierig, Code zu schreiben, der auf jede Situation (einschließlich der unglücklichen) angemessen reagiert. Dies liegt jedoch daran, dass das Schreiben von fehlerfreiem Code mühsam und schwierig ist und nicht daran, dass Sie Fehlercodes übergeben.
Sowohl Raymond Chen als auch Joel haben einige beredte Argumente gegen die Verwendung von Ausnahmen für alles vorgebracht.
nodiscard
Attribut ein, das eine Compilerwarnung ausgibt, wenn der Rückgabewert einer Funktion nicht gespeichert wird. Hilft ein wenig, vergessene Fehlercode-Überprüfungen abzufangen. Beispiel: godbolt.org/g/6i6E0BNormalerweise bevorzuge ich Ausnahmen, weil sie mehr Kontextinformationen enthalten und den Fehler (bei richtiger Verwendung) dem Programmierer klarer vermitteln können.
Auf der anderen Seite sind Fehlercodes leichter als Ausnahmen, aber schwieriger zu pflegen. Die Fehlerprüfung kann versehentlich weggelassen werden. Fehlercodes sind schwieriger zu pflegen, da Sie einen Katalog mit allen Fehlercodes führen und dann das Ergebnis einschalten müssen, um zu sehen, welcher Fehler ausgelöst wurde. Fehlerbereiche können hier hilfreich sein, denn wenn wir nur daran interessiert sind, ob ein Fehler vorliegt oder nicht, ist es einfacher zu überprüfen (z. B. ist ein HRESULT-Fehlercode größer oder gleich 0 Erfolg und kleiner als Null ist ein Fehler). Sie können versehentlich weggelassen werden, da der Entwickler nicht programmgesteuert nach Fehlercodes sucht. Auf der anderen Seite können Sie Ausnahmen nicht ignorieren.
Zusammenfassend bevorzuge ich in fast allen Situationen Ausnahmen gegenüber Fehlercodes.
quelle
Ich bevorzuge Ausnahmen, weil
quelle
goto
Fehlercodes können von den Aufrufern Ihrer Funktionen ignoriert werden (und sind es oft!). Ausnahmen zwingen sie zumindest dazu, den Fehler auf irgendeine Weise zu behandeln. Auch wenn ihre Version des Umgangs damit darin besteht, einen leeren Fanghandler zu haben (Seufzer).
quelle
Ausnahmen über Fehlercodes, kein Zweifel. Sie erhalten von Ausnahmen weitgehend die gleichen Vorteile wie bei Fehlercodes, aber auch viel mehr, ohne die Mängel von Fehlercodes. Der einzige Grund für Ausnahmen ist, dass der Aufwand etwas höher ist. In der heutigen Zeit sollte dieser Aufwand für fast alle Anwendungen als vernachlässigbar angesehen werden.
Hier sind einige Artikel, in denen die beiden Techniken diskutiert, verglichen und gegenübergestellt werden:
Es gibt einige gute Links in denen, die Sie weiterlesen können.
quelle
Ich würde die beiden Modelle niemals mischen ... es ist zu schwierig, von einem zum anderen zu konvertieren, wenn Sie von einem Teil des Stapels, der Fehlercodes verwendet, zu einem höheren Teil wechseln, das Ausnahmen verwendet.
Ausnahmen sind "alles, was die Methode oder Unterroutine daran hindert oder hindert, das zu tun, was Sie von ihr verlangt haben" ... KEINE Nachrichten über Unregelmäßigkeiten oder ungewöhnliche Umstände oder den Zustand des Systems usw. zurückzugeben. Verwenden Sie Rückgabewerte oder ref (oder out) Parameter dafür.
Ausnahmen ermöglichen das Schreiben (und Verwenden) von Methoden mit einer Semantik, die von der Funktion der Methode abhängt. Das heißt, eine Methode, die ein Employee-Objekt oder eine Liste von Employees zurückgibt, kann dazu eingegeben werden, und Sie können sie durch Aufrufen verwenden.
Bei Fehlercodes geben alle Methoden einen Fehlercode zurück. Für diejenigen, die etwas anderes zurückgeben müssen, um vom aufrufenden Code verwendet zu werden, müssen Sie eine Referenzvariable übergeben, die mit diesen Daten gefüllt werden soll, und den Rückgabewert für das testen Fehlercode und behandeln Sie ihn bei jedem Funktions- oder Methodenaufruf.
Wenn Sie so codieren, dass jede Methode nur eine einfache Aufgabe ausführt, sollten Sie eine Ausnahme auslösen, wenn die Methode das gewünschte Ziel der Methode nicht erreichen kann. Ausnahmen sind viel umfangreicher und auf diese Weise einfacher zu verwenden als Fehlercodes. Ihr Code ist viel sauberer - Der Standardfluss des "normalen" Codepfads kann ausschließlich dem Fall gewidmet werden, in dem die Methode das erreichen kann, was Sie wollten ... Und dann den Code zum Bereinigen oder Behandeln des Codes "außergewöhnliche" Umstände, in denen etwas Schlimmes passiert, das den erfolgreichen Abschluss der Methode verhindert, können vom normalen Code getrennt werden. Wenn Sie die Ausnahme dort, wo sie aufgetreten ist, nicht behandeln können und sie den Stapel an eine Benutzeroberfläche weitergeben müssen (oder schlimmer noch, über die Leitung von einer Mid-Tier-Komponente zu einer Benutzeroberfläche), dann mit dem Ausnahmemodell:
quelle
In der Vergangenheit bin ich dem Fehlercode-Camp beigetreten (habe zu viel C-Programmierung gemacht). Aber jetzt habe ich das Licht gesehen.
Ja, Ausnahmen belasten das System ein wenig. Sie vereinfachen jedoch den Code und reduzieren die Anzahl der Fehler (und WTFs).
Verwenden Sie also eine Ausnahme, aber verwenden Sie sie mit Bedacht. Und sie werden dein Freund sein.
Als Anmerkung. Ich habe gelernt zu dokumentieren, welche Ausnahme mit welcher Methode ausgelöst werden kann. Leider wird dies von den meisten Sprachen nicht benötigt. Dies erhöht jedoch die Wahrscheinlichkeit, die richtigen Ausnahmen auf der richtigen Ebene zu behandeln.
quelle
Es kann einige Situationen geben, in denen die Verwendung von Ausnahmen auf saubere, klare und korrekte Weise umständlich ist, aber die überwiegende Mehrheit der Zeitausnahmen ist die offensichtliche Wahl. Der größte Vorteil der Ausnahmebehandlung gegenüber Fehlercodes besteht darin, dass der Ausführungsfluss geändert wird, was aus zwei Gründen wichtig ist.
Wenn eine Ausnahme auftritt, folgt die Anwendung nicht mehr ihrem "normalen" Ausführungspfad. Der erste Grund, warum dies so wichtig ist, ist, dass das Programm angehalten wird und keine unvorhersehbaren Dinge mehr tut, wenn der Autor des Codes nicht wirklich alles daran setzt, schlecht zu sein. Wenn ein Fehlercode nicht überprüft wird und keine geeigneten Maßnahmen als Reaktion auf einen fehlerhaften Fehlercode ergriffen werden, macht das Programm weiter, was es tut, und wer weiß, was das Ergebnis dieser Aktion sein wird. Es gibt viele Situationen, in denen das Programm "was auch immer" tun kann, was sehr teuer werden kann. Stellen Sie sich ein Programm vor, das Leistungsinformationen für verschiedene Finanzinstrumente abruft, die ein Unternehmen verkauft, und diese Informationen an Makler / Großhändler weiterleitet. Wenn etwas schief geht und das Programm weiter läuft, Es könnte fehlerhafte Leistungsdaten an die Makler und Großhändler senden. Ich kenne niemanden sonst, aber ich möchte nicht derjenige sein, der in einem VPs-Büro sitzt und erklärt, warum mein Code dazu geführt hat, dass das Unternehmen Bußgelder im Wert von 7 Ziffern erhalten hat. Die Übermittlung einer Fehlermeldung an Kunden ist im Allgemeinen der Übermittlung falscher Daten vorzuziehen, die als "echt" erscheinen könnten, und die letztere Situation ist mit einem viel weniger aggressiven Ansatz wie Fehlercodes viel einfacher zu lösen.
Der zweite Grund, warum ich Ausnahmen und deren Unterbrechung der normalen Ausführung mag, ist, dass es viel, viel einfacher ist, die Logik „normale Dinge passieren“ von der Logik „etwas ist schief gelaufen“ zu trennen. Für mich ist dies:
... ist dem vorzuziehen:
Es gibt noch andere kleine Dinge über Ausnahmen, die auch nett sind. Eine Reihe von bedingten Logik zu haben, um zu verfolgen, ob bei einer der in einer Funktion aufgerufenen Methoden ein Fehlercode zurückgegeben wurde, und diesen Fehlercode höher zurückzugeben, ist eine Menge Kesselplatte. In der Tat ist es eine Menge Kesselplatte, die schief gehen kann. Ich habe viel mehr Vertrauen in das Ausnahmesystem der meisten Sprachen als in ein Rattennest von If-else-if-else-Aussagen, die Fred geschrieben hat, und ich habe viel bessere Dinge zu tun mit meiner Zeit als Code Überprüfung der Ratte Nest.
quelle
Sie sollten beide verwenden. Die Sache ist zu entscheiden, wann jeder verwendet werden soll .
Es gibt einige Szenarien, in denen Ausnahmen die offensichtliche Wahl sind :
In einigen Situationen können Sie mit dem Fehlercode nichts anfangen , und Sie müssen ihn nur auf einer höheren Ebene im Aufrufstapel behandeln , normalerweise nur den Fehler protokollieren, dem Benutzer etwas anzeigen oder das Programm schließen. In diesen Fällen müssten Sie bei Fehlercodes die Fehlercodes manuell Stufe für Stufe aufblasen, was mit Ausnahmen offensichtlich viel einfacher ist. Der Punkt ist, dass dies für unerwartete und nicht handhabbare Situationen ist.
In Bezug auf Situation 1 (in der etwas Unerwartetes und Unhandhabbares passiert, das Sie einfach nicht protokollieren möchten) können Ausnahmen hilfreich sein, da Sie möglicherweise Kontextinformationen hinzufügen . Wenn ich beispielsweise eine SqlException in meinen untergeordneten Datenhelfern erhalte, möchte ich diesen Fehler in der untergeordneten Ebene abfangen (wo ich den SQL-Befehl kenne, der den Fehler verursacht hat), damit ich diese Informationen erfassen und mit zusätzlichen Informationen erneut werfen kann . Bitte beachten Sie hier das Zauberwort: neu werfen und nicht schlucken . Die erste Regel für die Ausnahmebehandlung: Schlucken Sie keine Ausnahmen . Beachten Sie außerdem, dass mein innerer Fang nichts protokollieren muss, da der äußere Fang den gesamten Stack-Trace enthält und diesen möglicherweise protokolliert.
In einigen Situationen haben Sie eine Folge von Befehlen, und wenn einer von ihnen fehlschlägt , sollten Sie Ressourcen bereinigen / entsorgen (*), unabhängig davon, ob es sich um eine nicht behebbare Situation handelt (die ausgelöst werden sollte) oder um eine wiederherstellbare Situation (in diesem Fall können Sie dies lokal oder im Anrufercode behandeln, aber Sie brauchen keine Ausnahmen). Offensichtlich ist es viel einfacher, alle diese Befehle in einem einzigen Versuch zu platzieren, anstatt Fehlercodes nach jeder Methode zu testen und im finally-Block zu bereinigen / zu entsorgen. Bitte beachten Sie, dass Sie , wenn Sie möchten, dass der Fehler in die Luft sprudelt (was wahrscheinlich das ist, was Sie wollen), ihn nicht einmal abfangen müssen - Sie verwenden nur das endgültige zum Bereinigen / Entsorgen - Sie sollten catch / retrow nur verwenden, wenn Sie möchten Kontextinformationen hinzufügen (siehe Punkt 2).
Ein Beispiel wäre eine Folge von SQL-Anweisungen innerhalb eines Transaktionsblocks. Auch dies ist eine "unhandhabbare" Situation, selbst wenn Sie sich entschließen, sie frühzeitig zu fangen (lokal behandeln, anstatt nach oben zu sprudeln). Es ist immer noch eine fatale Situation, in der das beste Ergebnis darin besteht, alles abzubrechen oder zumindest einen großen abzubrechen Teil des Prozesses.
(*) Dies ist wie das
on error goto
, was wir in alten Visual Basic verwendet habenIn Konstruktoren können Sie nur Ausnahmen auslösen.
In allen anderen Situationen, in denen Sie Informationen zurückgeben, für die der Anrufer Maßnahmen ergreifen kann / sollte , ist die Verwendung von Rückkehrcodes wahrscheinlich die bessere Alternative. Dies schließt alle erwarteten "Fehler" ein , da sie wahrscheinlich vom unmittelbaren Aufrufer behandelt werden sollten und kaum zu viele Ebenen im Stapel hochgeblasen werden müssen.
Natürlich ist es immer möglich, erwartete Fehler als Ausnahmen zu behandeln und dann sofort eine Ebene darüber abzufangen, und es ist auch möglich, jede Codezeile in einem Try-Catch zu erfassen und für jeden möglichen Fehler Maßnahmen zu ergreifen. IMO, dies ist ein schlechtes Design, nicht nur, weil es viel ausführlicher ist, sondern insbesondere, weil die möglichen Ausnahmen, die möglicherweise ausgelöst werden, ohne Lesen des Quellcodes nicht offensichtlich sind - und Ausnahmen von jeder tiefen Methode ausgelöst werden können, wodurch unsichtbare Gotos entstehen . Sie unterbrechen die Codestruktur, indem sie mehrere unsichtbare Austrittspunkte erstellen, die das Lesen und Überprüfen von Code erschweren. Mit anderen Worten, Sie sollten niemals Ausnahmen als Flusskontrolle verwenden, weil das für andere schwer zu verstehen und aufrechtzuerhalten wäre. Es kann sogar schwierig werden, alle möglichen Codeflüsse zum Testen zu verstehen.
Nochmals: Für eine korrekte Bereinigung / Entsorgung können Sie try-finally verwenden, ohne etwas zu fangen .
Die populärste Kritik an Rückkehrcodes ist, dass "jemand die Fehlercodes ignorieren könnte, aber im gleichen Sinne kann jemand auch Ausnahmen verschlucken. Eine schlechte Ausnahmebehandlung ist bei beiden Methoden einfach . Das Schreiben eines guten fehlercodebasierten Programms ist jedoch immer noch viel einfacher als ein ausnahmebasiertes Programm zu schreiben . Und wenn einer aus irgendeinem Grund beschließt, alle Fehler (die alten
on error resume next
) zu ignorieren , können Sie dies leicht mit Rückkehrcodes tun, und Sie können dies nicht ohne viele Try-Catches tun.Die zweitbeliebteste Kritik an Rückkehrcodes ist, dass "es schwierig ist, in die Luft zu sprudeln" - aber das liegt daran, dass die Leute nicht verstehen, dass Ausnahmen für nicht wiederherstellbare Situationen gelten, während Fehlercodes dies nicht tun.
Die Entscheidung zwischen Ausnahmen und Fehlercodes ist eine Grauzone. Es ist sogar möglich, dass Sie einen Fehlercode von einer wiederverwendbaren Geschäftsmethode erhalten müssen, und dann entscheiden Sie sich, diesen in eine Ausnahme zu packen (möglicherweise Informationen hinzuzufügen) und ihn in die Luft sprudeln zu lassen. Es ist jedoch ein Konstruktionsfehler anzunehmen, dass ALLE Fehler als Ausnahmen ausgelöst werden sollten.
Etwas zusammenfassen:
Ich verwende gerne Ausnahmen, wenn ich eine unerwartete Situation habe, in der nicht viel zu tun ist, und normalerweise möchten wir einen großen Codeblock oder sogar die gesamte Operation oder das gesamte Programm abbrechen. Dies ist wie das alte "on error goto".
Ich verwende gerne Rückkehrcodes, wenn ich Situationen erwartet habe, in denen der Anrufercode Maßnahmen ergreifen kann / sollte. Dies umfasst die meisten Geschäftsmethoden, APIs, Validierungen usw.
Dieser Unterschied zwischen Ausnahmen und Fehlercodes ist eines der Entwurfsprinzipien der GO-Sprache, die "Panik" für schwerwiegende unerwartete Situationen verwendet, während regelmäßig erwartete Situationen als Fehler zurückgegeben werden.
Bei GO sind jedoch auch mehrere Rückgabewerte zulässig , was bei der Verwendung von Rückkehrcodes sehr hilfreich ist, da Sie gleichzeitig einen Fehler und etwas anderes zurückgeben können. Unter C # / Java können wir dies ohne Parameter, Tupel oder (meine Lieblings-) Generika erreichen, die in Kombination mit Aufzählungen dem Aufrufer eindeutige Fehlercodes liefern können:
Wenn ich meiner Methode eine neue mögliche Rückgabe hinzufüge, kann ich sogar alle Aufrufer überprüfen, ob sie diesen neuen Wert beispielsweise in einer switch-Anweisung abdecken. Mit Ausnahmen kann man das wirklich nicht machen. Wenn Sie Rückkehrcodes verwenden, kennen Sie normalerweise alle möglichen Fehler im Voraus und testen sie. Mit Ausnahmen wissen Sie normalerweise nicht, was passieren könnte. Das Umschließen von Aufzählungen in Ausnahmen (anstelle von Generika) ist eine Alternative (solange klar ist, welche Art von Ausnahmen jede Methode auslösen wird), aber IMO ist das Design immer noch schlecht.
quelle
Meine Argumentation wäre, wenn Sie einen Low-Level-Treiber schreiben, der wirklich Leistung benötigt, und dann Fehlercodes verwenden. Wenn Sie diesen Code jedoch in einer übergeordneten Anwendung verwenden und ein wenig Overhead bewältigen kann, schließen Sie diesen Code mit einer Schnittstelle ein, die diese Fehlercodes überprüft und Ausnahmen auslöst.
In allen anderen Fällen sind Ausnahmen wahrscheinlich der richtige Weg.
quelle
Ich kann hier auf dem Zaun sitzen, aber ...
In Python ist die Verwendung von Ausnahmen Standard, und ich bin sehr glücklich, meine eigenen Ausnahmen zu definieren. In C gibt es überhaupt keine Ausnahmen.
In C ++ (zumindest in der STL) werden Ausnahmen normalerweise nur für wirklich außergewöhnliche Fehler ausgelöst (ich sehe sie selbst praktisch nie). Ich sehe keinen Grund, in meinem eigenen Code etwas anderes zu tun. Ja, es ist einfach, Rückgabewerte zu ignorieren, aber C ++ zwingt Sie auch nicht, Ausnahmen abzufangen. Ich denke, man muss sich nur angewöhnen, es zu tun.
Die Codebasis, an der ich arbeite, ist hauptsächlich C ++ und wir verwenden fast überall Fehlercodes, aber es gibt ein Modul, das Ausnahmen für Fehler auslöst, einschließlich sehr ungewöhnlicher, und der gesamte Code, der dieses Modul verwendet, ist ziemlich schrecklich. Dies kann jedoch nur daran liegen, dass wir Ausnahmen und Fehlercodes gemischt haben. Der Code, der konsequent Fehlercodes verwendet, ist viel einfacher zu bearbeiten. Wenn unser Code konsequent Ausnahmen verwendet, wäre es vielleicht nicht so schlimm. Das Mischen der beiden scheint nicht so gut zu funktionieren.
quelle
Da ich mit C ++ arbeite und RAII habe, um die Verwendung sicher zu machen, verwende ich fast ausschließlich Ausnahmen. Es zieht die Fehlerbehandlung aus dem normalen Programmablauf und macht die Absicht klarer.
Ich lasse jedoch Ausnahmen für außergewöhnliche Umstände. Wenn ich erwarte, dass ein bestimmter Fehler häufig auftritt, überprüfe ich, ob der Vorgang erfolgreich ist, bevor ich ihn ausführe, oder rufe eine Version der Funktion auf, die stattdessen Fehlercodes verwendet (Gefällt mir
TryParse()
).quelle
Methodensignaturen sollten Ihnen mitteilen, was die Methode tut. So etwas wie long errorCode = getErrorCode (); mag in Ordnung sein, aber long errorCode = fetchRecord (); ist verwirrend.
quelle
Mein Ansatz ist, dass wir beide, dh Ausnahmen- und Fehlercodes, gleichzeitig verwenden können.
Ich werde verwendet, um verschiedene Arten von Ausnahmen zu definieren (z. B. DataValidationException oder ProcessInterruptExcepion) und in jeder Ausnahme eine detailliertere Beschreibung jedes Problems zu definieren.
Ein einfaches Beispiel in Java:
Auf diese Weise verwende ich Ausnahmen, um Kategoriefehler zu definieren, und Fehlercodes, um detailliertere Informationen über das Problem zu definieren.
quelle
throw new DataValidationException("The input is too small")
? Einer der Vorteile von Ausnahmen besteht darin, detaillierte Informationen zuzulassen.Ausnahmen gelten für außergewöhnliche Umstände, dh wenn sie nicht Teil des normalen Codeflusses sind.
Es ist durchaus legitim, Ausnahmen und Fehlercodes zu mischen, wobei Fehlercodes den Status von etwas darstellen und nicht einen Fehler bei der Ausführung des Codes an sich (z. B. Überprüfen des Rückkehrcodes eines untergeordneten Prozesses).
Aber wenn ein außergewöhnlicher Umstand eintritt, glaube ich, dass Ausnahmen das ausdrucksstärkste Modell sind.
Es gibt Fälle, in denen Sie möglicherweise Fehlercodes anstelle von Ausnahmen bevorzugen oder verwenden müssen, und diese wurden bereits angemessen behandelt (abgesehen von anderen offensichtlichen Einschränkungen wie der Compilerunterstützung).
Wenn Sie jedoch in die andere Richtung gehen und Ausnahmen verwenden, können Sie noch höhere Abstraktionen für Ihre Fehlerbehandlung erstellen, wodurch Ihr Code noch ausdrucksvoller und natürlicher wird. Ich würde wärmstens empfehlen, diesen ausgezeichneten, aber unterschätzten Artikel des C ++ - Experten Andrei Alexandrescu zum Thema "Enforcements" zu lesen: http://www.ddj.com/cpp/184403864 . Obwohl es sich um einen C ++ - Artikel handelt, sind die Prinzipien allgemein anwendbar, und ich habe das Durchsetzungskonzept recht erfolgreich in C # übersetzt.
quelle
Erstens stimme ich Toms Antwort zu dass für High-Level-Inhalte Ausnahmen verwendet werden und für Low-Level-Inhalte Fehlercodes verwendet werden, sofern es sich nicht um Service Oriented Architecture (SOA) handelt.
In SOA, wo Methoden auf verschiedenen Computern aufgerufen werden können, werden Ausnahmen möglicherweise nicht über die Leitung übertragen. Stattdessen verwenden wir Erfolgs- / Fehlerantworten mit einer Struktur wie unten (C #):
Und verwenden Sie wie folgt:
Wenn diese in Ihren Serviceantworten konsistent verwendet werden, entsteht ein sehr schönes Muster für die Behandlung von Erfolg / Misserfolg in der Anwendung. Dies ermöglicht eine einfachere Fehlerbehandlung bei asynchronen Aufrufen innerhalb von Diensten sowie zwischen Diensten.
quelle
Ich würde Ausnahmen für alle Fehlerfälle bevorzugen, außer wenn ein Fehler ein erwartbares fehlerfreies Ergebnis einer Funktion ist, die einen primitiven Datentyp zurückgibt. Wenn Sie beispielsweise den Index eines Teilstrings in einer größeren Zeichenfolge finden, wird normalerweise -1 zurückgegeben, wenn er nicht gefunden wird, anstatt eine NotFoundException auszulösen.
Die Rückgabe ungültiger Zeiger, die möglicherweise dereferenziert sind (z. B. NullPointerException in Java verursachen), ist nicht zulässig.
Die Verwendung mehrerer verschiedener numerischer Fehlercodes (-1, -2) als Rückgabewerte für dieselbe Funktion ist normalerweise ein schlechter Stil, da Clients möglicherweise eine "== -1" -Prüfung anstelle von "<0" durchführen.
Eine Sache, die Sie hier beachten sollten, ist die Entwicklung der APIs im Laufe der Zeit. Eine gute API ermöglicht es, das Fehlerverhalten auf verschiedene Arten zu ändern und zu erweitern, ohne Clients zu beschädigen. Wenn beispielsweise ein Client-Fehlerhandle auf 4 Fehlerfälle überprüft wurde und Sie Ihrer Funktion einen fünften Fehlerwert hinzufügen, testet der Client-Handler dies möglicherweise nicht und bricht ab. Wenn Sie Ausnahmen auslösen, wird dies für Clients normalerweise einfacher, auf eine neuere Version einer Bibliothek zu migrieren.
Eine andere zu berücksichtigende Sache ist, wenn Sie in einem Team arbeiten, wo eine klare Linie für alle Entwickler gezogen werden muss, um eine solche Entscheidung zu treffen. ZB "Ausnahmen für High-Level-Sachen, Fehlercodes für Low-Level-Sachen" ist sehr subjektiv.
In jedem Fall, in dem mehr als ein trivialer Fehlertyp möglich ist, sollte der Quellcode niemals das numerische Literal verwenden, um einen Fehlercode zurückzugeben oder ihn zu behandeln (Rückgabe -7, wenn x == -7 ...), aber immer eine benannte Konstante (return NO_SUCH_FOO, wenn x == NO_SUCH_FOO).
quelle
Wenn Sie unter einem großen Projekt arbeiten, können Sie nicht nur Ausnahmen oder nur Fehlercodes verwenden. In verschiedenen Fällen sollten Sie unterschiedliche Ansätze verwenden.
Beispielsweise möchten Sie nur Ausnahmen verwenden. Sobald Sie sich jedoch für die asynchrone Ereignisverarbeitung entschieden haben. In diesen Situationen ist es nicht ratsam, Ausnahmen für die Fehlerbehandlung zu verwenden. Die Verwendung von Fehlercodes überall in der Anwendung ist jedoch mühsam.
Daher ist es meiner Meinung nach normal, Ausnahmen und Fehlercodes gleichzeitig zu verwenden.
quelle
Für die meisten Anwendungen sind Ausnahmen besser. Die Ausnahme ist, wenn die Software mit anderen Geräten kommunizieren muss. Die Domäne, in der ich arbeite, sind industrielle Steuerungen. Hier werden Fehlercodes bevorzugt und erwartet. Meine Antwort ist also, dass es von der Situation abhängt.
quelle
Ich denke, es hängt auch davon ab, ob Sie wirklich Informationen wie Stack-Trace aus dem Ergebnis benötigen. Wenn ja, entscheiden Sie sich auf jeden Fall für eine Ausnahme, die ein Objekt mit vielen Informationen zum Problem enthält. Wenn Sie jedoch nur am Ergebnis interessiert sind und sich nicht darum kümmern, warum dieses Ergebnis angezeigt wird, wählen Sie den Fehlercode.
Beispiel: Wenn Sie eine Datei bearbeiten und mit IOException konfrontiert sind, ist der Client möglicherweise daran interessiert zu wissen, von wo aus dies ausgelöst wurde, eine Datei zu öffnen oder eine Datei zu analysieren usw. Sie sollten also besser IOException oder seine spezifische Unterklasse zurückgeben. In einem Szenario, in dem Sie eine Anmeldemethode haben und wissen möchten, ob diese erfolgreich war oder nicht, geben Sie entweder nur einen Booleschen Wert zurück oder geben einen Fehlercode zurück, um die richtige Meldung anzuzeigen. Hier ist der Client nicht daran interessiert zu wissen, welcher Teil der Logik diesen Fehlercode verursacht hat. Er weiß nur, ob sein Berechtigungsnachweis ungültig ist oder die Kontosperre usw.
Ein anderer Anwendungsfall, an den ich denken kann, ist, wenn Daten im Netzwerk übertragen werden. Ihre Remote-Methode kann anstelle von Exception nur Fehlercode zurückgeben, um die Datenübertragung zu minimieren.
quelle
Meine allgemeine Regel lautet:
quelle
Fehlercodes funktionieren auch nicht, wenn Ihre Methode etwas anderes als einen numerischen Wert zurückgibt ...
quelle