485 Stimmen

Ist es besser, null oder eine leere Sammlung zurückzugeben?

Das ist eine Art eine allgemeine Frage (aber ich bin mit C#), was ist der beste Weg (Best Practice), geben Sie null oder leere Sammlung für eine Methode, die eine Sammlung als Rückgabetyp hat?

0 Stimmen

Dies ist eine subjektive Frage, bei der es auf beiden Seiten leidenschaftliche Gläubige gibt. Es gibt keine allgemein anerkannte "beste Praxis".

5 Stimmen

1 Stimmen

Nun, es gibt eine bewährte Praxis, von der es aber auch begründete Ausnahmen gibt.

19voto

Jay Punkte 26044

Meines Erachtens sollten Sie den Wert zurückgeben, der im Kontext semantisch korrekt ist, was auch immer das sein mag. Eine Regel, die besagt, dass man immer eine leere Sammlung zurückgeben sollte, erscheint mir etwas zu simpel.

Nehmen wir an, dass wir in einem System für ein Krankenhaus eine Funktion haben, die eine Liste aller früheren Krankenhausaufenthalte der letzten 5 Jahre zurückgeben soll. Wenn der Kunde noch nicht im Krankenhaus war, ist es sinnvoll, eine leere Liste zurückzugeben. Was aber, wenn der Kunde diesen Teil des Einweisungsformulars leer gelassen hat? Wir brauchen einen anderen Wert, um "leere Liste" von "keine Antwort" oder "weiß nicht" zu unterscheiden. Wir könnten eine Ausnahme auslösen, aber das ist nicht notwendigerweise eine Fehlerbedingung, und es bringt uns nicht unbedingt aus dem normalen Programmfluss heraus.

Ich war schon oft von Systemen frustriert, die nicht zwischen Null und keiner Antwort unterscheiden können. Ich habe schon einige Male erlebt, dass ein System mich aufgefordert hat, eine Zahl einzugeben, ich gebe eine Null ein und erhalte eine Fehlermeldung, dass ich einen Wert in dieses Feld eingeben muss. Das habe ich gerade getan: Ich habe Null eingegeben! Aber das System akzeptiert die Null nicht, weil es sie nicht von keiner Antwort unterscheiden kann.


Antwort an Saunders:

Ja, ich gehe davon aus, dass es einen Unterschied zwischen "Person hat die Frage nicht beantwortet" und "Die Antwort war Null" gibt. Das war der Sinn des letzten Absatzes meiner Antwort. Viele Programme sind nicht in der Lage, "weiß nicht" von "leer" oder "Null" zu unterscheiden, was mir ein potenziell schwerwiegender Fehler zu sein scheint. Ich habe zum Beispiel vor etwa einem Jahr ein Haus gekauft. Ich besuchte eine Immobilien-Website, und dort waren viele Häuser mit einer Preisvorstellung von 0 $ aufgelistet, was sich für mich ziemlich gut anhörte: Sie geben diese Häuser umsonst weg! Aber ich bin sicher, die traurige Wahrheit war, dass sie den Preis einfach nicht eingegeben hatten. In diesem Fall werden Sie vielleicht sagen: "Nun, offensichtlich bedeutet Null, dass sie den Preis nicht eingegeben haben - niemand wird ein Haus umsonst verschenken." Auf der Website wurden jedoch auch die durchschnittlichen Kauf- und Verkaufspreise für Häuser in verschiedenen Städten angegeben. Ich kann nicht umhin, mich zu fragen, ob der Durchschnitt die Nullen nicht mit einschließt, so dass sich für einige Orte ein falsch niedriger Durchschnitt ergibt. z. B. was ist der Durchschnitt von 100.000 $, 120.000 $ und "weiß nicht"? Technisch gesehen lautet die Antwort "weiß nicht". Was wir wahrscheinlich wirklich sehen wollen, ist $110.000. Was wir aber wahrscheinlich erhalten werden, ist 73.333 $, was völlig falsch wäre. Und was wäre, wenn wir dieses Problem auf einer Website hätten, auf der die Benutzer online bestellen können? (Unwahrscheinlich bei Immobilien, aber ich bin sicher, Sie haben das schon bei vielen anderen Produkten gesehen.) Würden wir wirklich wollen, dass "Preis noch nicht festgelegt" als "kostenlos" interpretiert wird?

RE mit zwei getrennten Funktionen, einer "Gibt es eine?" und einer "Wenn ja, welche?" Ja, das könnte man natürlich machen, aber warum sollte man das wollen? Jetzt muss das aufrufende Programm zwei Aufrufe machen, statt einem. Was passiert, wenn ein Programmierer das "any?" nicht aufruft und direkt zum "what is it?" übergeht? ? Gibt das Programm eine irreführende Null zurück? Eine Ausnahme auslösen? Einen undefinierten Wert zurückgeben? Das erzeugt mehr Code, mehr Arbeit und mehr potenzielle Fehler.

Der einzige Vorteil, den ich darin sehe, ist, dass Sie damit eine willkürliche Vorschrift einhalten können. Hat diese Vorschrift irgendeinen Vorteil, der es wert macht, dass man sie befolgt? Wenn nicht, warum sich die Mühe machen?


Antwort an Jammycakes:

Überlegen Sie, wie der eigentliche Code aussehen würde. Ich weiß, in der Frage stand C#, aber entschuldigen Sie, wenn ich Java schreibe. Mein C# ist nicht sehr scharf und das Prinzip ist das gleiche.

Mit einer Null-Rückgabe:

HospList list=patient.getHospitalizationList(patientId);
if (list==null)
{
   // ... handle missing list ...
}
else
{
  for (HospEntry entry : list)
   //  ... do whatever ...
}

Mit einer separaten Funktion:

if (patient.hasHospitalizationList(patientId))
{
   // ... handle missing list ...
}
else
{
  HospList=patient.getHospitalizationList(patientId))
  for (HospEntry entry : list)
   // ... do whatever ...
}

Mit der Null-Rückgabe sind es sogar ein oder zwei Zeilen weniger Code, so dass der Aufrufer nicht mehr, sondern weniger belastet wird.

Ich sehe nicht, wie dadurch ein DRY-Problem entsteht. Es ist ja nicht so, dass wir den Aufruf zweimal ausführen müssen. Wenn wir immer das Gleiche tun wollten, wenn die Liste nicht existiert, könnten wir vielleicht die Behandlung in die Funktion get-list verlagern, anstatt sie dem Aufrufer zu überlassen, so dass es eine DRY-Verletzung wäre, den Code in den Aufrufer zu stellen. Aber wir wollen mit Sicherheit nicht immer das Gleiche tun. In Funktionen, bei denen wir die Liste zur Verarbeitung benötigen, ist eine fehlende Liste ein Fehler, der die Verarbeitung unterbrechen könnte. Aber auf einer Eingabemaske wollen wir die Verarbeitung sicher nicht unterbrechen, wenn der Benutzer noch keine Daten eingegeben hat: Wir wollen ihn Daten eingeben lassen. Die Behandlung von "keine Liste" muss also auf die eine oder andere Weise auf der Ebene des Anrufers erfolgen. Und ob wir das mit einer Null-Rückgabe oder einer separaten Funktion tun, macht keinen Unterschied für das übergeordnete Prinzip.

Klar, wenn der Aufrufer nicht auf Null prüft, kann das Programm mit einer Null-Zeiger-Ausnahme fehlschlagen. Aber wenn es eine separate "got any"-Funktion gibt und der Aufrufer diese Funktion nicht aufruft, sondern blindlings die "get list"-Funktion aufruft, was passiert dann? Wenn sie eine Ausnahme auslöst oder anderweitig fehlschlägt, ist das so ziemlich das Gleiche, was passieren würde, wenn sie null zurückgibt und nicht darauf prüft. Wenn sie eine leere Liste zurückgibt, ist das einfach falsch. Du unterscheidest nicht zwischen "Ich habe eine Liste mit null Elementen" und "Ich habe keine Liste". Das ist so, als würde man für den Preis null zurückgeben, wenn der Benutzer keinen Preis eingegeben hat: Das ist einfach falsch.

Ich verstehe nicht, wie das Anhängen eines zusätzlichen Attributs an die Sammlung helfen soll. Der Aufrufer muss es immer noch überprüfen. Inwiefern ist das besser als die Prüfung auf Null? Nochmals: Das Schlimmste, was passieren kann, ist, dass der Programmierer vergisst, es zu prüfen, und falsche Ergebnisse liefert.

Eine Funktion, die null zurückgibt, ist keine Überraschung, wenn der Programmierer mit dem Konzept von null vertraut ist, das "keinen Wert haben" bedeutet, und ich denke, dass jeder kompetente Programmierer davon gehört haben sollte, ob er es für eine gute Idee hält oder nicht. Ich denke, eine separate Funktion ist eher ein "Überraschungsproblem". Wenn ein Programmierer mit der API nicht vertraut ist, wird er, wenn er einen Test ohne Daten durchführt, schnell feststellen, dass er manchmal eine Null zurückbekommt. Aber wie würde er die Existenz einer anderen Funktion entdecken, wenn er nicht auf die Idee käme, dass es eine solche Funktion geben könnte, und wenn er in der Dokumentation nachschaut, und die Dokumentation ist vollständig und verständlich? Ich hätte viel lieber eine Funktion, die mir immer eine sinnvolle Antwort gibt, als zwei Funktionen, die ich kennen und mir merken muss, um beide aufzurufen.

4 Stimmen

Warum ist es notwendig, die Antworten "keine Antwort" und "Null" in demselben Rückgabewert zu kombinieren? Stattdessen sollte die Methode "frühere Krankenhausaufenthalte in den letzten fünf Jahren" zurückgeben und eine separate Methode die Frage "Wurde die Liste der früheren Krankenhausaufenthalte jemals ausgefüllt?" beantworten. Das setzt voraus, dass es einen Unterschied zwischen einer ausgefüllten Liste ohne frühere Krankenhausaufenthalte und einer nicht ausgefüllten Liste gibt.

0 Stimmen

@Saunders: Siehe mein Edit. Meine Antwort war zu lang, um in einen Kommentar zu passen, wortkarger Windbeutel, der ich bin.

2 Stimmen

Aber wenn Sie null zurückgeben, belasten Sie den Aufrufer sowieso schon zusätzlich! Der Aufrufer muss jeden Rückgabewert auf Null prüfen - eine schreckliche DRY-Verletzung. Wenn Sie gesondert angeben wollen, dass der Aufrufer die Frage nicht beantwortet hat, dann est Es ist einfacher, einen zusätzlichen Methodenaufruf zu erstellen, um diese Tatsache anzuzeigen. Entweder dies oder die Verwendung eines abgeleiteten Sammlungstyps mit einer zusätzlichen Eigenschaft DeclinedToAnswer. Die Regel, niemals null zurückzugeben, ist keineswegs willkürlich, sondern entspricht dem Prinzip der kleinsten Überraschung. Außerdem sollte der Rückgabetyp Ihrer Methode das bedeuten, was der Name besagt. Null tut das mit ziemlicher Sicherheit nicht.

11voto

David Hedlund Punkte 125085

Wenn eine leere Auflistung semantisch sinnvoll ist, ziehe ich es vor, diese zurückzugeben. Die Rückgabe einer leeren Sammlung für GetMessagesInMyInbox() kommuniziert "Sie haben wirklich keine Nachrichten in Ihrem Posteingang", während die Rückgabe null könnte nützlich sein, um mitzuteilen, dass nicht genügend Daten zur Verfügung stehen, um zu sagen, wie die Liste, die zurückgegeben werden könnte, aussehen sollte.

6 Stimmen

In dem von Ihnen genannten Beispiel klingt es so, als sollte die Methode wahrscheinlich eine Ausnahme auslösen, wenn sie die Anforderung nicht erfüllen kann, anstatt einfach null zurückzugeben. Ausnahmen sind viel nützlicher für die Diagnose von Problemen als Nullen.

0 Stimmen

Nun ja, im Beispiel des Posteingangs ist ein null Wert erscheint sicherlich nicht vernünftig, ich habe da eher allgemein gedacht. Ausnahmen sind auch großartig, um die Tatsache zu kommunizieren, dass etwas schief gelaufen ist, aber wenn die "unzureichenden Daten", auf die Bezug genommen wird, vollkommen erwartet werden, dann wäre es schlechtes Design, dort eine Ausnahme zu machen. Ich denke eher an ein Szenario, in dem es durchaus möglich und kein Fehler ist, dass die Methode manchmal nicht in der Lage ist, eine Antwort zu berechnen.

7voto

Dan Punkte 10793

Man könnte argumentieren, dass die Argumentation hinter Null-Objekt-Muster ist ähnlich wie eine, die die leere Sammlung zurückgibt.

6voto

Karmic Coder Punkte 17092

Die Rückgabe von null könnte effizienter sein, da kein neues Objekt erstellt wird. Allerdings würde dies auch oft eine null Prüfung (oder Ausnahmebehandlung).

Semantisch, null und eine leere Liste bedeuten nicht dasselbe. Die Unterschiede sind subtil, und in bestimmten Fällen kann die eine Wahl besser sein als die andere.

Wie auch immer Sie sich entscheiden, dokumentieren Sie es, um Verwirrung zu vermeiden.

8 Stimmen

Die Effizienz sollte fast nie ein Faktor sein, wenn es um die Korrektheit des Entwurfs einer API geht. In einigen sehr spezifischen Fällen, wie z.B. bei Grafikprimitiven, mag das so sein, aber wenn es um Listen und die meisten anderen High-Level-Dinge geht, bezweifle ich es sehr.

0 Stimmen

Ich stimme Greg zu, insbesondere wenn man bedenkt, dass der Code, den der API-Benutzer schreiben muss, um diese "Optimierung" zu kompensieren, ineffizienter sein kann, als wenn von vornherein ein besseres Design verwendet worden wäre.

0 Stimmen

Das stimmt, und in den meisten Fällen lohnt sich die Optimierung einfach nicht. Leere Listen sind mit moderner Speicherverwaltung praktisch kostenlos.

4voto

Jason Baker Punkte 180981

Ich würde sagen, dass null ist nicht dasselbe wie eine leere Sammlung, und Sie sollten diejenige wählen, die am besten repräsentiert, was Sie zurückgeben wollen. In den meisten Fällen null ist nichts (außer in SQL). Eine leere Sammlung ist etwas, wenn auch ein leeres Etwas.

Wenn Sie sich für das eine oder das andere entscheiden müssen, würde ich sagen, dass Sie eher zu einer leeren Sammlung als zu null tendieren sollten. Aber es gibt Zeiten, in denen eine leere Sammlung nicht dasselbe ist wie ein Nullwert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X