it-swarm.com.de

Null oder eine leere Wert- / Wurfausnahme zurückgeben?

Verschiedene Programmierbücher schlagen vor, dass Methoden keine null -Werte zurückgeben sollten (z. B. Clean Code). Anstatt null zurückzugeben, sollten Standardwerte (0 oder leere Zeichenfolge oder leeres Objekt) zurückgegeben oder eine Ausnahme ausgelöst werden. Dies wird empfohlen, um viele != null - Prüfungen oder NullPointerException zu vermeiden.

Ich verstehe wirklich nicht, wie das hilft. Wenn Sie einen Standardwert zurückgeben, müssen Sie != DEFAULT Überprüfen. Darüber hinaus kann der Standardwert etwas bedeuten (z. B. 0 für einen Kreditbetrag). Das Auslösen einer bestimmten Ausnahme lohnt sich nicht, denn wenn Sie mit Ihrem Code nicht gut umgehen, wird trotzdem eine Ausnahme ausgelöst - NullPointerException.

Ich habe darüber nachgedacht, als ich einen Fehler gefunden habe, der durch eine Methode verursacht wurde, die ein leeres Objekt (z. B. new MyBean()) zurückgegeben hat, anstatt null zurückzugeben. Der Code funktionierte nicht und die Protokolle warnten nichts, so dass das Erkennen und Beheben nicht so einfach war. mit null wäre ein NullPointerException geworfen worden, so dass das Erkennen und Beheben des Fehlers trivial gewesen wäre.

Der einzige Fall, in dem es für mich sinnvoll ist, einen Standardwert zurückzugeben, anstatt null zurückzugeben, ist die Rückgabe von Arrays/Sammlungen. hier werden sie normalerweise verbraucht for each element in collection. Wenn es also leer ist, passiert nichts, aber wenn es null ist, wird NPE geworfen.

10
m3th0dman

Verschiedene Programmierbücher schlagen vor, dass Methoden keine Nullwerte zurückgeben sollten (z. B. Clean Code). Anstatt Null zurückzugeben, sollten Standardwerte (0 oder leere Zeichenfolge oder leeres Objekt) zurückgegeben oder eine Ausnahme ausgelöst werden. Dies wird empfohlen, um viele! = Null-Überprüfungen oder NullPointerException zu vermeiden.

Es ist erwähnenswert und ein weit verbreitetes Missverständnis, dass Herr Martin nicht behauptet hat, Sie sollten immer eine Ausnahme auslösen und nie einen Fehlerwert zurückgeben. Tatsächlich liest sich die relevante Passage ganz anders, wenn Sie sie sorgfältig lesen (ich habe hier keine englische Version, daher muss ich sie zurückübersetzen, sorry):

Wenn Sie einen null Zeiger zurückgeben möchten, sollten Sie stattdessen eine Ausnahme auslösen.

Beachten Sie, dass dort " überlege " steht, nicht "du sollst".

Eine weitere gute Lektüre sind diese beiden:


PS: Originaltext aus meiner deutschen Ausgabe:

Wenn Sie versucht sind, einen Nullzeiger zu geben, zu haben, zu verlieren, zu einer Ausnahme zu werfen.

11
JensG

Meiner Meinung nach ist null für Einzelwert-Rückgabemethoden der Rückgabe einer leeren oder Standardinstanz eines Typs weit überlegen. Standardwerte können nicht nur Fehler maskieren, sondern abhängig von der Komplexität des Typs auch komplexe, schwer zu dokumentierende Abhängigkeiten zwischen Methoden erzeugen, da die API-Hersteller und API-Konsumenten eine konsistente Vorstellung davon haben müssen, welche/welche Werte fehlerhafte Ergebnisse darstellen.

Wenn es dagegen um Sammlungen geht, ist die Rückgabe einer leeren Sammlung der Rückgabe von null weit überlegen, da der Aufrufer der Methode erwartet, dass eine variable Anzahl von Ergebnissen erzielt werden kann, sodass eine leere Sammlung eine konzeptionell gültige darstellt Ergebnis und ist symmetrisch mit dem Konzept der leeren Menge in der Mathematik.

Ausnahmen haben jedoch ihren Platz, insbesondere wenn eine Methode void oder unit zurückgibt.

4
Aluan Haddad

Es ist von entscheidender Bedeutung, zwischen Methoden zu unterscheiden, bei denen Fehler auftreten sollen, und solchen, bei denen dies nicht der Fall ist. Ebenso wichtig ist ein klares Verständnis des Vertrags für diese Methode.

Wenn es sich bei der Methode um eine Methode handelt, bei der routinemäßig ein Fehler auftritt (z. B. das Abrufen von Daten aus einer Datenbank), muss eine Methode zum Zurückgeben von Erfolg/Fehler sowie zum Zurückgeben der Daten vorhanden sein. Normalerweise bevorzuge ich die Rückgabe von true/false für den Vorgang und einen separaten Aufruf zum Abrufen der Daten und/oder des Status.

Wenn bei der Methode kein Fehler erwartet wird (z. B. das Zurückgeben eines Elements aus einer Sammlung nach Index), sollte nie null zurückgeben. Es sollte ein gültiges Element zurückgeben oder eine Ausnahme auslösen oder bestätigen. Anrufer sollten nie das Rückgabeergebnis überprüfen, da es immer gültig ist.

Es kann zweckmäßig sein, einen Standardwert zurückzugeben, anstatt ihn zu bestätigen. Dies sollte sich jedoch im Methodenvertrag widerspiegeln, und es können zwei Methoden vorhanden sein (GetXxx und GetXxxOrDefault).

Eine weit verbreitete Überprüfung der Rückgabewerte gegen Null ist häufig symptomatisch für tiefere Probleme im Code. Ratschläge, die in neueren Programmierbüchern zu finden sind, sind solide.


Betrachten Sie als Antwort auf Kommentare den Fall, in dem eine Methode zum Durchführen einer Suche, Berechnung, Analyse usw. erforderlich ist und ein Fehler routinemäßig auftritt. Ich mag Ausnahmen und das TryParse () - Formular nicht, weil sie den Codefluss unterbrechen, während das FindOrDefault () - Formular ein Problem darstellt, wenn der Standardwert ein zulässiger Rückgabewert ist. Ich bevorzuge diesen Wrapper:

public static U SafeLookup<T, U>(this Dictionary<T, U> dict, T key, U missing = default(U)) {
  U ret;
  if (dict.TryGetValue(key, out ret)) return ret;
  return missing;
}

Es wird immer ein Wert zurückgegeben, und der Wert, der bei einem Fehler zurückgegeben werden soll, kann optional angegeben werden.

2
david.pfx

Ich mag die Idee, eine Ausnahme auszulösen, anstatt null oder einen anderen Fehlerwert zurückzugeben. Angenommen, ich entwerfe eine neue Klasse, die ein XML eines bestimmten Formats analysiert. Ich möchte, dass meine Klasse nur einen Einstiegspunkt hat, dh einen Konstruktor, der den Pfad zu einer gültigen XML-Datei angibt. Im Gegenzug erhalte ich ein Objekt mit einer Reihe von Eigenschaften und Methoden, das den Inhalt meiner XML-Datei enthält und mir einige Informationen dazu gibt.

Wie kann ich nun beispielsweise sicherstellen, dass mein Pfad zur XML-Datei gültig war? Ich kann beispielsweise eine Load(string xmlPath) - Funktion in meiner Klasse haben. Was sollte der Rückgabetyp sein? Sollte es ein bool oder int zurückgeben oder was? Und am interessantesten ist, wie kann ich das überprüfen? Idealerweise sollte ich die Funktion Loadprivate erstellen und mich nicht einmal darum kümmern, dass sie existiert. Aber wenn ich das Ergebnis von Load überprüfen möchte, sollte die Funktion public gemacht werden. Oder übergeben Sie eine bool loadSuccesful-Variable an meinen Konstruktor und füllen Sie diese mit dem Ergebnis des Ladens der Datei. Aber warten Sie, was ist, wenn ich meine XML -Datei mit einer XSD vergleichen möchte? Ich muss eine andere Funktion haben, parseXmlSchema(string xmlPath) oder so ähnlich. Was soll es bei einem Ausfall zurückgeben? Und wie können Sie die Informationen aus Ihrer Klasse herausholen und gleichzeitig eine saubere Oberfläche beibehalten? Möglicherweise sind auch andere Validierungen erforderlich.

Wenn Sie diese Art von Methoden privat machen und eine Ausnahme auslösen, wenn etwas schief geht (es macht wirklich keinen Sinn, Ihre XML-Datei zu analysieren, wenn sie nicht gültig ist), können Sie eine saubere Schnittstelle haben und Ihre Klasse in einer try/catch- Anweisung verwenden . Sie können Ihren Klassenkonstruktor mit nur einem string -Parameter haben (oder zwei, wenn Sie das XSD -Schema zählen). Wenn in der Anweisung try alles in Ordnung ist, wenn nichts schief gelaufen ist, keine Ausnahmen ausgelöst wurden, Pfade vorhanden sind usw., ist Ihr Programm zufrieden. Wenn Sie sich derzeit in der mittleren Ebene Ihrer App befinden und ein FileNotFoundException von Ihren unteren Ebenen erhalten, können Sie rethrow das an Ihren Benutzer (GUI) weitergeben, um etwas dagegen zu unternehmen. Die GUI-Ebene könnte es in diesem Moment abfangen und den Benutzer beispielsweise über eine MessageBox benachrichtigen und als Bonus protokollieren. Der Benutzer probiert dann eine andere XML-Datei aus und fährt mit der Geschichte fort. Wenn Sie alle möglichen Ausnahmen abfangen und dem Benutzer aussagekräftige Informationen anzeigen oder im Hintergrund die entsprechenden Maßnahmen ergreifen, muss Ihre Anwendung nicht einfrieren (das haben Sie wahrscheinlich gesehen), wenn Sie dies befürchten.

Als Bonus können Sie an dem Punkt, an dem Ihre Ausnahme ausgelöst wurde, alle Arten von aussagekräftigen Informationen übergeben, z. B. Nachrichten, Parameternamen, Zeilennummern, Funktionsnamen usw. Wenn Sie Ihren Code dokumentieren (wie Sie sollten), dokumentieren Sie die Ausnahmen, die a Klasse/Methode kann werfen.

1
mihai