Ich habe einige Stimmen gehört, die sagten, dass das Überprüfen auf einen zurückgegebenen Nullwert von Methoden ein schlechtes Design ist. Ich würde gerne einige Gründe dafür hören.
Pseudocode:
variable x = object.method()
if (x is null) do something
oop
null
return-value
koen
quelle
quelle
Antworten:
Der Grund dafür, dass null nicht zurückgegeben wird, ist, dass Sie nicht danach suchen müssen und daher Ihr Code nicht einem anderen Pfad folgen muss, der auf dem Rückgabewert basiert. Vielleicht möchten Sie das Null-Objektmuster überprüfen, das weitere Informationen dazu enthält.
Wenn ich beispielsweise eine Methode in Java definieren würde, die eine Sammlung zurückgibt, würde ich normalerweise lieber eine leere Sammlung (dh
Collections.emptyList()
) als null zurückgeben, da dies bedeutet, dass mein Clientcode sauberer ist. z.B... was sauberer ist als:
quelle
null
ist ein "Container", der null oder einen Zeiger auf Objekte enthält. (So wird esMaybe
in diesen Fällen sicherlich explizit von Haskell modelliert und ist dafür umso besser.)Hier ist der Grund.
In Clean Code von Robert Martin schreibt er, dass die Rückgabe von null ein schlechtes Design ist, wenn Sie stattdessen beispielsweise ein leeres Array zurückgeben können. Da das erwartete Ergebnis ein Array ist, warum nicht? Sie können das Ergebnis ohne zusätzliche Bedingungen durchlaufen. Wenn es eine ganze Zahl ist, reicht vielleicht 0 aus, wenn es ein Hash ist, leerer Hash. etc.
Die Voraussetzung ist, den aufrufenden Code nicht zu zwingen, Probleme sofort zu behandeln. Der aufrufende Code möchte sich möglicherweise nicht mit ihnen befassen. Das ist auch der Grund, warum Ausnahmen in vielen Fällen besser sind als Null.
quelle
Gute Verwendung der Rückgabe von null:
Schlechte Verwendung: Der Versuch, Ausnahmesituationen zu ersetzen oder zu verbergen, wie z.
In diesen Fällen ist das Auslösen einer Ausnahme angemessener, da:
Ausnahmen sollten jedoch nicht verwendet werden, um normale Programmbetriebsbedingungen wie:
quelle
boolean login(String,String)
scheint in Ordnung zu sein und so auchAuthenticationContext createAuthContext(String,String) throws AuthenticationException
Ja, die Rückgabe von NULL ist in einer objektorientierten Welt ein schreckliches Design . Kurz gesagt, die Verwendung von NULL führt zu:
In diesem Blog-Beitrag finden Sie eine ausführliche Erklärung: http://www.yegor256.com/2014/05/13/why-null-is-bad.html . Mehr in meinem Buch Elegant Objects , Abschnitt 4.1.
quelle
bool TryGetBlah(out blah)
oderFirstOrNull()
oderMatchOrFallback(T fallbackValue)
.isEmpty()
), und nur dann, wenn dies der Fall ist, die Methode aufrufen. Die Leute argumentieren gegen die zweite, dass es eine schlechtere Leistung ist - aber wie Unix-Philosophie sagt, "schätzen Sie die menschliche Zeit gegenüber der Maschinenzeit" (dh eine trivial langsamere Leistung verschwendet weniger Zeit als Entwickler, die Code debuggen, der falsche Fehler verursacht).Wer sagt, dass dies schlechtes Design ist?
Das Überprüfen auf Nullen ist eine gängige Praxis, die sogar empfohlen wird. Andernfalls besteht überall das Risiko von NullReferenceExceptions. Es ist besser, den Fehler ordnungsgemäß zu behandeln, als Ausnahmen auszulösen, wenn dies nicht erforderlich ist.
quelle
Basierend auf dem, was Sie bisher gesagt haben, denke ich, dass es nicht genug Informationen gibt.
Die Rückgabe von null von einer CreateWidget () -Methode scheint schlecht zu sein.
Die Rückgabe von null von einer FindFooInBar () -Methode scheint in Ordnung zu sein.
quelle
Create...
Gibt eine neue Instanz zurück oder wirft ;Get...
gibt eine erwartete vorhandene Instanz zurück oder wirft ;GetOrCreate...
gibt eine vorhandene Instanz oder eine neue Instanz zurück, wenn keine vorhanden ist, oder wirft ;Find...
gibt eine vorhandene Instanz zurück, falls vorhanden, odernull
. Bei Sammlungsabfragen - gibtGet...
immer eine Sammlung zurück, die leer ist, wenn keine übereinstimmenden Elemente gefunden werden.Sein Erfinder sagt, es sei ein Milliardenfehler!
quelle
Dies hängt von der verwendeten Sprache ab. Wenn Sie in einer Sprache wie C # arbeiten, in der das Fehlen eines Werts idiomatisch darin besteht, null zurückzugeben, ist die Rückgabe von null ein gutes Design, wenn Sie keinen Wert haben. Alternativ wäre in Sprachen wie Haskell, die die Vielleicht-Monade für diesen Fall idiomatisch verwenden, die Rückgabe von Null ein schlechtes Design (wenn es überhaupt möglich wäre).
quelle
null
in Sprachen wie C # und Java oft überladen ist und in der Domäne eine gewisse Bedeutung hat. Wenn Sie dasnull
Schlüsselwort in den Sprachspezifikationen nachschlagen, bedeutet dies einfach "ein ungültiger Zeiger". Das bedeutet wahrscheinlich nichts in irgendeiner Problemdomäne.null
oder einen "nicht initialisierten" handeltnull
Wenn Sie alle Antworten lesen, wird klar, dass die Antwort auf diese Frage von der Art der Methode abhängt.
Erstens, wenn etwas Außergewöhnliches passiert (IO-Problem usw.), werden logisch Ausnahmen ausgelöst. Wenn genau etwas außergewöhnlich ist, ist es wahrscheinlich etwas für ein anderes Thema.
Wann immer erwartet wird, dass eine Methode möglicherweise keine Ergebnisse liefert, gibt es zwei Kategorien:
Leere Enumrables, Strings usw. sind gute Beispiele
Wie bereits erwähnt, wird angenommen, dass die Methode möglicherweise kein Ergebnis hat, daher ist sie keine Ausnahme und sollte daher keine Ausnahme auslösen. Ein neutraler Wert ist nicht möglich (Beispiel: 0 ist je nach Programm kein besonders neutrales Ergebnis)
Bis wir eine offizielle Möglichkeit haben, zu kennzeichnen, dass eine Funktion null zurückgeben kann oder nicht, versuche ich, eine Namenskonvention zu haben, um dies zu kennzeichnen.
Genau wie Sie die Try Something () - Konvention für Methoden haben, von denen erwartet wird, dass sie fehlschlagen, nenne ich meine Methoden häufig Safe Something () wenn die Methode ein neutrales Ergebnis anstelle von null zurückgibt.
Ich bin mit dem Namen noch nicht ganz einverstanden, könnte mir aber nichts Besseres einfallen lassen. Also renne ich jetzt damit.
quelle
Ich habe eine Tagung in diesem Bereich, die mir gute Dienste geleistet hat
Für Einzelartikelabfragen:
Create...
Gibt eine neue Instanz zurück oder wirftGet...
Gibt eine erwartete vorhandene Instanz zurück oder wirftGetOrCreate...
Gibt eine vorhandene Instanz oder eine neue Instanz zurück, wenn keine vorhanden ist, oder löst ausFind...
gibt eine vorhandene Instanz zurück, falls vorhanden, odernull
Für Sammlungsabfragen:
Get...
Gibt immer eine Sammlung zurück, die leer ist, wenn keine passenden [1] Elemente gefunden werden[1] gegeben einige explizite oder implizite Kriterien, die im Funktionsnamen oder als Parameter angegeben sind.
quelle
Get
wenn ich erwarte , dass es dort ist. Wenn es nicht vorhanden ist, ist es ein Fehler und ich werfe - ich muss den Rückgabewert nie überprüfen. Ich benutze,Find
wenn ich wirklich nicht weiß, ob es da ist oder nicht - dann muss ich den Rückgabewert überprüfen.Ausnahmen gelten für außergewöhnliche Umstände.
Wenn Ihre Funktion ein Attribut finden soll, das einem bestimmten Objekt zugeordnet ist, und dieses Objekt kein solches Attribut hat, kann es angebracht sein, null zurückzugeben. Wenn das Objekt nicht vorhanden ist, ist es möglicherweise besser, eine Ausnahme auszulösen. Wenn die Funktion eine Liste von Attributen zurückgeben soll und keine zurückgegeben werden soll, ist die Rückgabe einer leeren Liste sinnvoll - Sie geben alle Nullattribute zurück.
quelle
Es ist in Ordnung, null zurückzugeben, wenn dies in irgendeiner Weise sinnvoll ist:
In einem solchen Fall ist es sinnvoll, null zurückzugeben, wenn die ID keiner vorhandenen Entität entspricht, da Sie den Fall, in dem keine Übereinstimmung gefunden wurde, von einem legitimen Fehler unterscheiden können.
Die Leute denken möglicherweise, dass dies schlecht ist, weil es als "spezieller" Rückgabewert missbraucht werden kann, der auf einen Fehlerzustand hinweist, der nicht so gut ist, ähnlich wie das Zurückgeben von Fehlercodes von einer Funktion, aber verwirrend, weil der Benutzer die Rückgabe überprüfen muss null, anstatt die entsprechenden Ausnahmen abzufangen, z
quelle
Es ist nicht unbedingt ein schlechtes Design - wie bei so vielen Designentscheidungen kommt es darauf an.
Wenn das Ergebnis der Methode bei normaler Verwendung kein gutes Ergebnis liefert, ist die Rückgabe von null in Ordnung:
Wenn es wirklich immer ein Ergebnis ungleich Null geben sollte, ist es möglicherweise besser, eine Ausnahme auszulösen:
quelle
Optional<>
In bestimmten Szenarien möchten Sie einen Fehler sofort bemerken.
Das Überprüfen gegen NULL und das Nicht-Aktivieren (für Programmiererfehler) oder das Auslösen (für Benutzer- oder Anruferfehler) im Fehlerfall kann dazu führen, dass spätere Abstürze schwerer zu finden sind, da der ursprüngliche ungerade Fall nicht gefunden wurde.
Darüber hinaus kann das Ignorieren von Fehlern zu Sicherheits-Exploits führen. Vielleicht kam die Nullheit von der Tatsache, dass ein Puffer überschrieben wurde oder dergleichen. Jetzt stürzen Sie nicht ab , was bedeutet, dass der Exploiter die Möglichkeit hat, in Ihrem Code auszuführen.
quelle
Welche Alternativen sehen Sie zur Rückgabe von null?
Ich sehe zwei Fälle:
In diesem Fall könnten wir: Null zurückgeben oder eine (markierte) Ausnahme auslösen (oder vielleicht ein Element erstellen und zurückgeben)
In diesem Fall könnten wir Null zurückgeben, eine leere Liste zurückgeben oder eine Ausnahme auslösen.
Ich glaube, dass return null möglicherweise weniger gut ist als die Alternativen, da der Client daran denken muss, nach null zu suchen, Programmierer zu vergessen und zu codieren
In Java kann der Compiler durch Auslösen einer aktivierten Ausnahme, RecordNotFoundException, den Client daran erinnern, sich mit dem Fall zu befassen.
Ich finde, dass Suchen, die leere Listen zurückgeben, sehr praktisch sein können - füllen Sie einfach die Anzeige mit dem gesamten Inhalt der Liste, oh, es ist leer, der Code "funktioniert einfach".
quelle
Manchmal ist es richtig, NULL zurückzugeben, aber insbesondere wenn Sie mit Sequenzen verschiedener Art (Arrays, Listen, Strings, What-Have-You) arbeiten, ist es wahrscheinlich besser, eine Sequenz mit der Länge Null zurückzugeben führt zu kürzerem und hoffentlich verständlicherem Code, ohne dass der API-Implementierer viel mehr schreiben muss.
quelle
Lassen Sie sie nachträglich eine andere Methode aufrufen, um herauszufinden, ob der vorherige Aufruf null war. ;-) Hey, es war gut genug für JDBC
quelle
Die Grundidee hinter diesem Thread ist, defensiv zu programmieren. Das heißt, Code gegen das Unerwartete. Es gibt eine Reihe verschiedener Antworten:
Adamski schlägt vor, das Null-Objektmuster zu betrachten, wobei diese Antwort für diesen Vorschlag abgestimmt wird.
Michael Valenty schlägt auch eine Namenskonvention vor, um dem Entwickler mitzuteilen, was zu erwarten ist. ZeroConcept schlägt eine ordnungsgemäße Verwendung von Exception vor, wenn dies der Grund für NULL ist. Und andere.
Wenn wir die "Regel" festlegen, dass wir immer defensiv programmieren wollen, können wir sehen, dass diese Vorschläge gültig sind.
Wir haben aber zwei Entwicklungsszenarien.
Von einem Entwickler "verfasste" Klassen: Der Autor
Klassen, die von einem anderen (vielleicht) Entwickler "konsumiert" werden: dem Entwickler
Unabhängig davon, ob eine Klasse für Methoden mit einem Rückgabewert NULL zurückgibt oder nicht, muss der Entwickler testen, ob das Objekt gültig ist.
Wenn der Entwickler dies nicht kann, ist diese Klasse / Methode nicht deterministisch. Das heißt, wenn der "Methodenaufruf" zum Abrufen des Objekts nicht das tut, was er "ankündigt" (z. B. getEmployee), hat er den Vertrag gebrochen.
Als Autor einer Klasse möchte ich beim Erstellen einer Methode immer so freundlich und defensiv (und deterministisch) sein.
Da entweder NULL oder das NULL-OBJEKT (z. B. wenn (Mitarbeiter als NullEmployee.ISVALID)) überprüft werden muss und dies möglicherweise bei einer Sammlung von Mitarbeitern erforderlich ist, ist der Nullobjektansatz der bessere Ansatz.
Aber ich mag auch Michael Valentys Vorschlag, die Methode zu benennen, die null zurückgeben muss, z. B. getEmployeeOrNull.
Ein Autor, der eine Ausnahme auslöst, entfernt die Auswahl für den Entwickler, um die Gültigkeit des Objekts zu testen, was für eine Sammlung von Objekten sehr schlecht ist, und zwingt den Entwickler zur Ausnahmebehandlung, wenn er seinen konsumierenden Code verzweigt.
Als Entwickler, der die Klasse konsumiert, hoffe ich, dass der Autor mir die Möglichkeit gibt, die Nullsituation zu vermeiden oder zu programmieren, mit der ihre Klasse / Methoden konfrontiert sein könnten.
Als Entwickler würde ich also defensiv gegen NULL von einer Methode aus programmieren. Wenn der Autor mir einen Vertrag gegeben hat, der immer ein Objekt zurückgibt (NULL OBJECT immer) und dieses Objekt eine Methode / Eigenschaft hat, mit der die Gültigkeit des Objekts getestet werden kann, würde ich diese Methode / Eigenschaft verwenden, um das Objekt weiter zu verwenden , sonst ist das Objekt ungültig und ich kann es nicht verwenden.
Fazit ist, dass der Autor der Klasse / Methoden Mechanismen bereitstellen muss, die ein Entwickler in seiner defensiven Programmierung verwenden kann. Das heißt, eine klarere Absicht der Methode.
Der Entwickler sollte immer eine defensive Programmierung verwenden, um die Gültigkeit der von einer anderen Klasse / Methode zurückgegebenen Objekte zu testen.
Grüße
GregJF
quelle
Andere Optionen hierfür sind: Rückgabe eines Werts, der Erfolg anzeigt oder nicht (oder Typ eines Fehlers), aber wenn Sie nur einen booleschen Wert benötigen, der Erfolg / Misserfolg anzeigt, Rückgabe von Null für Fehler und eines Objekts für Erfolg nicht weniger korrekt sein, dann true / false zurückgeben und das Objekt über den Parameter abrufen. Ich persönlich sehe nichts Schlechtes darin, null zurückzugeben, um anzuzeigen, dass etwas schief gelaufen ist, und es später zu überprüfen (um tatsächlich zu wissen, ob es Ihnen gelungen ist oder nicht). Wenn Sie blind denken, dass Ihre Methode nicht NULL zurückgibt und Ihren Code dann darauf basiert, kann dies zu anderen, manchmal schwer zu findenden Fehlern führen (obwohl dies in den meisten Fällen nur zum Absturz Ihres Systems führt :), wie Sie verweisen werden 0x00000000 früher oder später).
Ein anderer Ansatz wäre die Verwendung von Ausnahmen, um Fehler anzuzeigen, aber hier - es gibt tatsächlich viel mehr Stimmen, die besagen, dass dies eine schlechte Praxis ist (da die Verwendung von Ausnahmen praktisch sein kann, aber viele Nachteile hat).
quelle
Null_Funktion @wikipedia
quelle
Nun, es hängt sicher vom Zweck der Methode ab ... Manchmal wäre es eine bessere Wahl, eine Ausnahme auszulösen. Es hängt alles von Fall zu Fall ab.
quelle
Wenn der Code so etwas wie:
Wenn Sie ein Dummy-Objekt haben, dessen execute () -Methode nichts bewirkt, und Sie dieses in den entsprechenden Fällen anstelle von Null zurückgeben, müssen Sie nicht nach dem Null-Fall suchen und können stattdessen einfach Folgendes tun:
Hier liegt das Problem also nicht zwischen der Überprüfung auf NULL und einer Ausnahme, sondern zwischen dem Anrufer, der spezielle Nichtfälle anders behandeln muss (auf welche Weise auch immer) oder nicht.
quelle
Für meinen Anwendungsfall musste ich eine Map from-Methode zurückgeben und dann nach einem bestimmten Schlüssel suchen. Wenn ich jedoch eine leere Map zurückgebe, führt dies zu einer NullPointerException, und es wird nicht viel anders sein, wenn anstelle einer leeren Map null zurückgegeben wird. Ab Java8 können wir jedoch Optional verwenden . Dies ist genau der Grund, warum das optionale Konzept eingeführt wurde.
quelle
Tag auch,
Die Rückgabe von NULL, wenn Sie kein neues Objekt erstellen können, ist für viele APIs Standard.
Warum zum Teufel es schlechtes Design ist, weiß ich nicht.
Bearbeiten: Dies gilt für Sprachen, in denen es keine Ausnahmen gibt, wie z. B. C, in denen dies seit vielen Jahren die Konvention ist.
HTH
'Avahappy,
quelle