Gibt die Rückgabe null schlechtes Design zurück? [geschlossen]


127

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

13
Ausarbeiten: Wo sind diese Leute, die sagen, dass es schlecht ist? Links?
JCollum

2
Wenn Sie die Methode kontrollieren können, können Sie Unit-Tests durchführen lassen, um sicherzustellen, dass sie niemals null zurückgibt. Andernfalls verstehe ich nicht, warum es eine schlechte Praxis wäre, nach diesem Aufruf zu überprüfen, ob sie null ist. Es ist vielleicht eine schlechte Praxis bei dieser Methode, null zurückzugeben, aber Sie müssen Ihren Code schützen
BlackTigerX

9
Das Auslösen von Ausnahmen, nur weil keine Daten zurückgegeben werden müssen, ist unglaublich ärgerlich. Der normale Programmablauf sollte keine Ausnahmen auslösen.
Thorarin

4
@ David: Das habe ich wirklich gesagt. Wenn eine Methode Daten zurückgeben soll, aber keine vorhanden sind, bedeutet dies, dass auch ein Fehler aufgetreten ist. Das ist kein normaler Programmablauf :)
Thorarin

2
@Thorarin: "normaler" Programmablauf ist ein ziemlich dehnbares Konzept: nicht wirklich eine solide Grundlage für ein Argument.
Tomislav Nakic-Alfirevic

Antworten:


206

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

Collection<? extends Item> c = getItems(); // Will never return null.

for (Item item : c) { // Will not enter the loop if c is empty.
  // Process item.
}

... was sauberer ist als:

Collection<? extends Item> c = getItems(); // Could potentially return null.

// Two possible code paths now so harder to test.
if (c != null) {
  for (Item item : c) {
    // Process item.
  }
}

6
Ja, viel besser als null zurückzugeben und zu hoffen, dass der Kunde sich daran erinnert, den Fall zu behandeln.
DJNA

10
Ich stimme gerne zu, dass die Rückgabe von null verrückt ist, wenn sie als Ersatz für leere Container (oder Zeichenfolgen) verwendet wird. Dies ist jedoch nicht der übliche Fall.
MSalters

2
+1 für das Null-Objektmuster auch für mich. Auch wenn ich tatsächlich null zurückgeben möchte, habe ich die Methode wie getCustomerOrNull () benannt, um sie explizit zu machen. Ich denke, eine Methode heißt gut, wenn der Leser sich die Implementierung nicht ansehen möchte.
Mike Valenty

4
Der Kommentar '// Zwei mögliche Codepfade jetzt' ist nicht korrekt; Sie haben in beiden Fällen zwei Codepfade. Mit dem null Collection-Objekt in Ihrem ersten Beispiel ist der Codepfad 'null' jedoch kürzer. Sie haben jedoch noch zwei Pfade und müssen noch zwei Pfade testen.
Frerich Raabe

1
@MSalters - wohl jede Variable in OO-Sprachen mit nullist ein "Container", der null oder einen Zeiger auf Objekte enthält. (So ​​wird es Maybein diesen Fällen sicherlich explizit von Haskell modelliert und ist dafür umso besser.)
Andrzej Doyle

71

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.


2
Dies ist das Null-Objekt-Muster, das in dieser Antwort erwähnt wird: stackoverflow.com/questions/1274792/…
Scott Dorman

Die Idee hier ist, dass Sie bei einem Fehler eine leere / leere Version des Objekttyps zurückgeben, den Sie normalerweise zurückgeben würden. Ein leeres Array oder eine leere Zeichenfolge würde beispielsweise für diese Fälle funktionieren. Die Rückgabe von "NULL" ist angemessen, wenn Sie normalerweise einen Zeiger zurückgeben würden (da NULL im Wesentlichen ein leerer Zeiger ist). Die Rückgabe von NULL bei einem Fehler von einer Funktion, die normalerweise beispielsweise einen Hash zurückgibt, kann verwirrend sein. Einige Sprachen handhaben dies besser als andere, aber im Allgemeinen ist Konsistenz die beste Vorgehensweise.
Bta

Sie kehren nicht unbedingt zu einem Fehler zurück, es sei denn, der Fehler steuert irgendwie den Ablauf (was keine gute Praxis ist) oder wird in einer API oder Schnittstelle abstrahiert. Fehler können sich auf jeder Ebene ausbreiten, auf der Sie sie abfangen möchten. Daher müssen Sie sich im aufrufenden Kontext nicht damit befassen. Sie sind standardmäßig nullobjektmusterfreundlich.
Max Chernyak

Leider berücksichtigt der aufrufende Code nicht immer den Fall einer leeren Sammlung (ähnlich wie der Nullfall). Das kann ein Problem sein oder auch nicht.
Sridhar Sarnobat

38

Gute Verwendung der Rückgabe von null:

  • Wenn null ein gültiges Funktionsergebnis ist , zum Beispiel: FindFirstObjectThatNeedsProcessing () kann null zurückgeben, wenn es nicht gefunden wird, und der Aufrufer sollte dies entsprechend überprüfen.

Schlechte Verwendung: Der Versuch, Ausnahmesituationen zu ersetzen oder zu verbergen, wie z.

  • catch (...) und gib null zurück
  • Die Initialisierung der API-Abhängigkeit ist fehlgeschlagen
  • Nicht genügend Speicherplatz
  • Ungültige Eingabeparameter (Programmierfehler, Eingaben müssen vom Anrufer bereinigt werden)
  • etc

In diesen Fällen ist das Auslösen einer Ausnahme angemessener, da:

  • Ein Null-Rückgabewert liefert keine aussagekräftigen Fehlerinformationen
  • Der unmittelbare Anrufer kann die Fehlerbedingung höchstwahrscheinlich nicht behandeln
  • Es gibt keine Garantie dafür, dass der Anrufer nach Nullergebnissen sucht

Ausnahmen sollten jedoch nicht verwendet werden, um normale Programmbetriebsbedingungen wie:

  • Ungültiger Benutzername / Passwort (oder vom Benutzer angegebene Eingaben)
  • Breaking Loops oder als nicht-lokale Gotos

7
"Ungültiger Benutzername" scheint jedoch ein guter Grund für eine Ausnahme zu sein.
Thilo

11
Benutzer, die ungültige Anmeldungen / Passwörter eingeben, sollten nicht als Ausnahmebedingungen behandelt werden, da dies Teil des normalen Programmbetriebs ist. Eine Ausnahmebedingung ist jedoch, dass das Authentifizierungssystem nicht reagiert (z. B. Active Directory).
ZeroConcept


2
Ich würde sagen, es kommt darauf an: boolean login(String,String)scheint in Ordnung zu sein und so auchAuthenticationContext createAuthContext(String,String) throws AuthenticationException
sfussenegger

1
Wenn in Ihrem Beispiel kein erstes Objekt verarbeitet werden muss, gibt es zwei sinnvolle Möglichkeiten, diesen Fall zu behandeln. Das erste ist das Nullobjektmuster. Erstellen Sie eine letzte Unterklasse, die eine nicht vorhandene Version der Klasse darstellt. Es hat vernünftige Standardeinstellungen und löst Ausnahmen aus, wenn Unsinnaktionen angefordert werden. Die andere Technik ist Option. Dies ist in Java8 und Scala verfügbar. Beides zeigt die Absicht der Entwickler. null kann keine Absicht zeigen, da es zu viele mögliche Bedeutungen hat. ** Absicht zeigen ** ist der wichtigste Aspekt des Codes.
Scott M.

29

Ja, die Rückgabe von NULL ist in einer objektorientierten Welt ein schreckliches Design . Kurz gesagt, die Verwendung von NULL führt zu:

  • Ad-hoc-Fehlerbehandlung (anstelle von Ausnahmen)
  • mehrdeutige Semantik
  • langsam statt schnell scheitern
  • Computerdenken statt Objektdenken
  • veränderbare und unvollständige Objekte

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.


2
Ich stimme voll und ganz zu. Ich mag nicht einmal das Nullobjektmuster, das eine "Tünche" -Verzögerungstaktik zu sein scheint. Entweder soll Ihre Methode immer erfolgreich sein oder nicht. Wenn es immer gelingen sollte, dann werfen. Wenn dies möglicherweise nicht erfolgreich ist, entwerfen Sie die Methode so, dass der Verbraucher sie kennt, z . B. bool TryGetBlah(out blah)oder FirstOrNull()oder MatchOrFallback(T fallbackValue).
Luke Puplett

Auch ich mag es nicht, null zurückzugeben. Sie trennen die Grundursache vom Symptom, was das Debuggen erschwert. Entweder eine Ausnahme auslösen (schnell fehlschlagen) oder eine Prüfmethode aufrufen, die zuerst einen Booleschen Wert zurückgibt (z. B. 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).
Sridhar Sarnobat

22

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.


11
+1. Code, der Ausnahmen für Probleme auslöst, die vor Ort behoben werden können, macht mich traurig.
Jkeys

6
Wie traurig werden Sie, wenn Codierer vergessen, nach Nullen zu suchen, und dann mysteriöse Nullzeigerausnahmen erhalten? Überprüfte Ausnahmen, bei denen der Compiler den Benutzer daran erinnert, dass er sich nicht mit Fehlerbedingungen befasst hat, vermeiden diese Klasse von Codierungsfehlern.
DJNA

3
@djna: Ich denke, das ist auch traurig, aber ich habe festgestellt, dass die gleiche Art von Codierern, die "vergessen", nach Nullen zu suchen, diejenigen sind, die sie häufig verschlucken, wenn sie mit geprüften Ausnahmen umgehen.
Randy unterstützt Monica

5
Es ist einfacher, das Vorhandensein eines leeren Fangblocks zu erkennen, als das Fehlen einer Nullprüfung.
Preston

20
@ Preston: Ich bin absolut anderer Meinung. Wenn kein Null-Check vorhanden ist, werden Sie ihn sofort erkennen, wenn er abstürzt. Verschluckte Ausnahmen können jahrelang mysteriöse und subtile Fehler
auslösen

18

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.


4
Ähnlich wie bei meiner Konvention: Einzelelementabfragen - 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 - gibt Get... immer eine Sammlung zurück, die leer ist, wenn keine übereinstimmenden Elemente gefunden werden.
Johann Gerell

NULL ist schlecht aus Gründen, die in der Antwort von yegor256 & hakuinin angegeben sind. Die Rückgabe eines gültigen, aber leeren Objekts vereinfacht die Argumentation insgesamt
Rob11311


10

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).


2
+1 für die Erwähnung vielleicht Monade. Ich finde, dass die Definition nullin Sprachen wie C # und Java oft überladen ist und in der Domäne eine gewisse Bedeutung hat. Wenn Sie das nullSchlüsselwort in den Sprachspezifikationen nachschlagen, bedeutet dies einfach "ein ungültiger Zeiger". Das bedeutet wahrscheinlich nichts in irgendeiner Problemdomäne.
MattDavey

Das Problem ist, dass Sie nicht wissen, ob es sich um einen "fehlenden Wert" nulloder einen "nicht initialisierten" handeltnull
CervEd

5

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:

  • Wenn es möglich ist, einen neutralen Wert zurückzugeben, tun Sie dies .
    Leere Enumrables, Strings usw. sind gute Beispiele
  • Wenn ein solcher neutraler Wert nicht vorhanden ist, sollte null zurückgegeben werden .
    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.


4

Ich habe eine Tagung in diesem Bereich, die mir gute Dienste geleistet hat

Für Einzelartikelabfragen:

  • 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 löst aus
  • Find...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.


Warum geben GetOne und FindOne unterschiedlich zurück, wenn sie nicht gefunden werden?
Vladimir Vukanac

Ich habe den Unterschied beschrieben. Ich verwende es, Getwenn 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, Findwenn ich wirklich nicht weiß, ob es da ist oder nicht - dann muss ich den Rückgabewert überprüfen.
Johann Gerell

3

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.


1
Wenn Sie versuchen , verwenden ein Attribut ohne Wert, dass Verdienste eine Ausnahme. (Ich gehe davon aus, dass Ihre Spezifikation besagt, dass das Attribut optional ist.) Verwenden Sie eine separate Methode, um zu überprüfen, ob der Wert festgelegt wurde.
Preston

3

Es ist in Ordnung, null zurückzugeben, wenn dies in irgendeiner Weise sinnvoll ist:

public String getEmployeeName(int id){ ..}

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

public Integer getId(...){
   try{ ... ; return id; }
   catch(Exception e){ return null;}
}

3
Jep. Wenn Sie eine Fehlerbedingung haben, lösen Sie eine Ausnahme aus.
David Thornley

3
Dies ist ein Fall, in dem eine Ausnahme gerechtfertigt wäre. Wenn Sie den Namen eines Mitarbeiters anfordern, der nicht existiert, läuft offensichtlich etwas schief.
Thorarin

Ich denke, das ist ein bisschen wörtlich, Thorarin - Sie können sicherlich mit meinem Beispiel streiten, aber ich bin sicher, Sie können sich eine Instanz einer Funktion vorstellen, die einen übereinstimmenden Wert zurückgibt, oder null, wenn es keine Übereinstimmung gibt. Wie wäre es, einen Wert von einem Schlüssel in einer Hashtabelle zu erhalten? (hätte an erster Stelle an dieses Beispiel denken sollen).
Steve B.

1
Eine Hash-Tabelle, die für einen nicht vorhandenen Schlüssel null zurückgibt, ist fehlerhaft. Dies bedeutet automatisch, dass Sie null nicht als Wert ohne inkonsistenten Code speichern können.
RHSeeger

3

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:

object x = GetObjectFromCache();   // return null if it's not in the cache

Wenn es wirklich immer ein Ergebnis ungleich Null geben sollte, ist es möglicherweise besser, eine Ausnahme auszulösen:

try {
   Controller c = GetController();    // the controller object is central to 
                                      //   the application. If we don't get one, 
                                      //   we're fubar

   // it's likely that it's OK to not have the try/catch since you won't 
   // be able to really handle the problem here
}
catch /* ... */ {
}

2
Obwohl Sie genau dort einen Diagnosefehler protokollieren können, können Sie die Ausnahme erneut auslösen. Manchmal kann die Datenerfassung bei einem ersten Fehler sehr hilfreich sein.
DJNA

Oder schließen Sie die Ausnahme in eine RuntimeException mit Diagnoseinformationen in der Nachrichtenzeichenfolge ein. Halten Sie die Informationen zusammen.
Thorbjørn Ravn Andersen

Jetzt (im Jahr 2018) kann ich nicht mehr zustimmen und in solchen Fällen sollten wir die Rückkehr bevorzugenOptional<>
Piotr Müller

2

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.


2

Welche Alternativen sehen Sie zur Rückgabe von null?

Ich sehe zwei Fälle:

  • findAnItem (id). Was soll dies tun, wenn der Artikel nicht gefunden wird?

In diesem Fall könnten wir: Null zurückgeben oder eine (markierte) Ausnahme auslösen (oder vielleicht ein Element erstellen und zurückgeben)

  • listItemsMatching (Kriterien) Was soll dies zurückgeben, wenn nichts gefunden wird?

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

x = find();
x.getField();  // bang null pointer exception

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".


3
Das Auslösen von Ausnahmen, um auf einen Zustand hinzuweisen, von dem erwartet wird, dass er möglicherweise während des normalen Programmablaufs auftritt, führt zu wirklich hässlichem Code der Art try {x = find ()} catch (RecordNotFound e) {// do stuff}.
quant_dev

Das Zurückgeben leerer Listen ist eine gute Lösung, jedoch nur, wenn sich die Methode in einem Kontext befindet, der Listen zurückgeben kann. Für "findById" -Situationen müssen Sie null zurückgeben. Ich mag keine RecordNotFound-Ausnahmen.
Thilo

Das ist also der Kern unserer Meinungsverschiedenheit. Für meine Augen gibt es keinen großen Unterschied in der Schönheit zwischen x = find (); if (x = null) {work} else {do ​​stuff} und versuche catch. Und wenn nötig, bin ich bereit, Schönheit für die Korrektheit des Codes zu opfern. Zu oft in meinem Leben stoße ich auf Code, bei dem die Rückgabewerte nicht überprüft wurden.
DJNA

1

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.



1

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


0

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).


0

Unbeabsichtigte Nullfunktionen können während der Entwicklung komplexer Programme auftreten, und wie toter Code weisen solche Vorkommnisse auf schwerwiegende Fehler in den Programmstrukturen hin.

Eine Nullfunktion oder -methode wird häufig als Standardverhalten einer wiederverwendbaren Funktion oder überschreibbaren Methode in einem Objektframework verwendet.

Null_Funktion @wikipedia


0

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.


0

Wenn der Code so etwas wie:

command = get_something_to_do()

if command:  # if not Null
    command.execute()

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:

get_something_to_do().execute()

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.


0

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.


-3

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,


2
Wenn Sie kein Objekt erstellen können, sollten Sie wirklich eine Ausnahme auslösen. Wenn Sie kein Objekt finden können, das einer Abfrage entspricht, müssen Sie null zurückgeben.
Thilo

@Thilo, zeig mir, wie das in C geht und ich werde am meisten interessiert sein.
Rob Wells

@RobWells C ist keine objektorientierte Sprache, aber diese Frage ist als "oop" markiert
yegor256

@ yegor256 Du hast recht. Und ich habe das ursprüngliche OOP-Tag verpasst. Aber wie BS sagte, ist eine Klasse in C ++ nur eine Struktur mit einigen zusätzlichen Mitgliedsfunktionen und einer ausgefallenen internen Speicherverwaltung. Wenn eine API jedoch eine Struktur zurückgeben soll, ist die Rückgabe von NUL, wenn Sie die Struktur nicht erstellen können, häufig die Konvention.
Rob Wells
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.