Warum erlaubt java.util.ArrayList das Hinzufügen von null?

41

Ich frage mich, warum java.util.ArrayListman das hinzufügen darf null. Gibt es einen Fall , wo ich möchte hinzufügen , nullum ein ArrayList?

Ich stelle diese Frage, weil wir in einem Projekt einen Fehler hatten, bei dem Code hinzugefügt wurde null, ArrayListund es schwierig war, zu erkennen, wo der Fehler war. Offensichtlich wurde ein NullPointerExceptiongeworfen, aber nicht, bis ein anderer Code versuchte, auf das Element zuzugreifen. Das Problem bestand darin, den Code zu finden, der das nullObjekt hinzugefügt hat . Es wäre einfacher gewesen, ArrayListeine Ausnahme im Code auszulösen, in dem die Elemente hinzugefügt wurden.

Alfredo Osorio
quelle
12
Das Guava-Projekt hat eine ziemlich interessante Seite zu diesem Thema (sie erlauben es nullin den meisten ihrer Sammlungen nicht).
Joachim Sauer
6
Ich glaube, dass die hier gegebenen Antworten die Frage gut abdecken. Vielleicht sollte eine Sache erwähnt werden: Nimm nicht alles, was im JDK ist, als holly und perfekt und schlage deinen Kopf, um zu verstehen, warum es so "perfekt" ist. Einige Dinge sind (ehrlich, IMHO) Fehler, die aufgrund der Abwärtskompatibilität dort geblieben sind und das ist es. Sogar die Java-Entwickler geben es zu, lesen Sie einfach Joshua Blochs Bücher, um seine Kritik an bestimmten Java-APIs zu sehen. Auf jeden Fall hängt Ihre Frage vom Wetter ab. Es gibt keinen eleganteren Weg, um NPE in Java zu erfassen. Die Antwort ist, nein, aber es sollte geben.
Shivan Dragon
2
Können Sie weitere Informationen darüber geben, warum dies nicht zulässig sein sollte? Wenn es nur um den Geschmack geht, sollte der weniger restriktive bevorzugt werden.
Mare Infinitus
Die einfache Antwort ist, dass dies nulldie Standardmethode ist, um fehlende Daten in Java darzustellen, egal ob Sie möchten oder nicht. Tatsächlich mögen es viele Leute nicht und machen es zu einem Argument für Dinge im funktionalen Programmierstil. Die am besten bewertete Antwort ergibt keinen Sinn / erfasst nicht das Wesentliche des Problems.
xji
@ JIXiang Sie vereinfachen, was nullist. "Missing" ist nur eine von mehreren möglichen Interpretationen von null. Andere gültige Interpretationen können "Unbekannt", "Nicht anwendbar" oder "Nicht initialisiert" sein. Was nulldarstellt, hängt von der Anwendung ab. Wie die Python-Community sagen würde: "Weigern Sie sich angesichts der Mehrdeutigkeit, die Versuchung zu erraten." Es wäre nur eine Vermutung, sich zu weigern, null in einem Behälter zu halten, der dazu in der Lage ist.
Riwalk

Antworten:

34

Diese Entwurfsentscheidung scheint hauptsächlich auf die Benennung zurückzuführen zu sein.

Der Name ArrayList empfiehlt dem Leser eine Funktionalität, die Arrays ähnelt - und es ist für Java Collections Framework- Designer selbstverständlich , dass die große Mehrheit der API-Benutzer davon ausgeht, dass sie ähnlich wie Arrays funktioniert.

Dies beinhaltet insbesondere die Behandlung von Nullelementen. API-Benutzer, die wissen, dass unten funktioniert OK:

array[0] = null; // NPE won't happen here

Es wäre ziemlich überrascht herauszufinden, ob ein ähnlicher Code für ArrayList NPE auslösen würde:

arrayList.set(0, null); // NPE => WTF?

Die obigen Überlegungen werden im JCF-Lernprogramm vorgestellt, in dem Punkte hervorgehoben werden, die auf eine enge Ähnlichkeit zwischen ArrayList- und einfachen Arrays hinweisen:

ArrayList ... bietet Positionszugriff mit konstanter Zeit und ist einfach nur schnell ...

Wenn Sie möchten, dass eine List-Implementierung keine Nullen zulässt, sollten Sie sie so NonNullableArrayListoder so ähnlich nennen, um zu vermeiden, dass API-Benutzer verwirrt werden.


Randnotiz: In den nachstehenden Kommentaren finden Sie eine Hilfsdiskussion sowie zusätzliche Überlegungen , die die hier dargelegte Argumentation stützen.

Mücke
quelle
12
Diese Erklärung kann nicht überzeugen, da sie LinkedList auchnull Listeneinträge unterstützt .
Stephen C
12
Ja ... aber eine einfachere und (IMO) plausibelere Erklärung ist, dass das Zulassen von nullEinträgen in vielen Fällen nützlich ist.
Stephen C
7
ArrayList wird nicht so aufgerufen, weil es ein Array nachahmt. Es heißt so, weil es eine Liste ist, die als Array implementiert ist. So wie sich eine TreeMap nicht wie ein Baum verhält.
Florian F
11
Diese Antwort, IMO, ist einfach falsch. Nullen sind zulässig, da in Java (IMO, schlechter) Null häufig verwendet wird, um nicht initialisierte oder fehlende Werte darzustellen. Wie kam es zu den meisten Abstimmungen und dem "Accept" -Check? Im Ernst, ich verliere heutzutage wirklich das Vertrauen in StackOverflow.
user949300
8
Diese Antwort ist einfach falsch. Dies ist nur eine nicht unterstützte Vermutung, dass Nullen in einer Listenimplementierung zulässig sind. Hier ist eine Zusammenfassung der Java-Sammlungen, die Nullen zulassen / nicht zulassen. Beachten Sie, dass es nichts mit Ähnlichkeit zu Arrays zu tun hat.
Andres F.
32

Null kann ein gültiger Wert für ein Element einer Liste sein. Angenommen, Ihre Liste enthält Elemente, die optionale Daten zu einer Benutzerliste darstellen und in derselben Reihenfolge wie die Benutzer gespeichert sind. Wenn die zusätzlichen Daten ausgefüllt sind, enthält Ihre Liste die zusätzlichen Daten, andernfalls ist der einem Benutzer entsprechende Steckplatz null. (Ich bin sicher, es gibt bessere Beispiele, aber Sie bekommen die Idee)

Wenn Sie nicht zulassen möchten, dass Nullen hinzugefügt werden, können Sie die Array-Liste mit einem eigenen Wrapper umschließen, der ausgelöst wurde, als Null hinzugefügt wurde.

Sam Holder
quelle
2
Dies scheint ein schlechtes Beispiel dafür zu sein, warum Nullen zulässig sein sollten - es gibt bessere Möglichkeiten, optionale Daten darzustellen, als Nullwerte in einer Liste zu verwenden.
Casablanca
@casablanca ja völlig einverstanden, es ist kein gutes Beispiel.
Sam Holder
Ich kann keinen guten Grund für eine ArrayList finden, Nullen zu enthalten, andere als schlechte Überraschungen für den nächsten Entwickler, um es zu "entdecken": /
AndreasScheinert
7
@casablanca Obwohl ich Ihnen zustimme, dass Nullen für die Darstellung optionaler Daten in Java vermieden werden sollten, ist dies "traditionell".
user949300
2
Ein solider Anwendungsfall: Sie möchten die Parameter als Liste an eine dynamische Funktion übergeben. Sie haben mehrere Funktionen mit jeweils unterschiedlichen Parametern, benötigen also ein Array mit dynamischer Größe und können immer null als gültiges Funktionsargument übergeben!
Falco,
19

ArrayListerlaubt null von Entwurf. Es ist beabsichtigt. Aus dem Javadoc :

"[ArrayList] ist eine Array-Implementierung mit veränderbarer Größe der List-Schnittstelle. Implementiert alle optionalen Listenoperationen und lässt alle Elemente zu, einschließlich Null ."

Die Antwort auf "warum" lautet, dass die ArrayList in Fällen, in denen ein nullin die Liste aufgenommen werden muss, nicht verwendet werden könnte, wenn dies nicht der Fall wäre . Im Gegensatz dazu können Sie verhindern, dass eine ArrayList Nullen enthält, indem Sie Werte entweder vor dem Hinzufügen testen oder einen Wrapper verwenden, der dies verhindert.

Gibt es einen Fall, in dem ich einer ArrayList null hinzufügen möchte?

Offensichtlich hat jeder Fall nulleine eindeutige Bedeutung. Dies kann beispielsweise bedeuten, dass der Wert an einer bestimmten Position in der Liste nicht initialisiert oder angegeben wurde.

Es wäre einfacher gewesen, wenn die ArrayList eine Ausnahme in dem Code ausgelöst hätte, in dem die Elemente hinzugefügt wurden.

Sie können dieses Verhalten problemlos implementieren, indem Sie eine Wrapper-Klasse erstellen. Dies ist jedoch nicht das Verhalten, das die meisten Programmierer / Anwendungen benötigen.

Stephen C
quelle
8

Gibt es einen Fall, in dem ich einer ArrayList null hinzufügen möchte?

Klar, was ist mit der Vorbelegung? Sie möchten eines ArrayListvon Dingen, die Sie noch nicht erstellen können, weil Sie nicht genügend Informationen haben. Nur weil Ihnen kein Grund einfällt, warum jemand etwas tun möchte, ist dies keine schlechte Idee. Wie auch immer. (Jetzt bin ich sicher, dass jemand mitkommt und sagt, Sie sollten stattdessen leere Objekte haben, die ein Muster erfüllen, über das sie in einem dunklen Blog gelesen haben, und dass Programmierer wirklich in der Lage sein sollten, Programme zu schreiben, ohne jemals ifAnweisungen zu verwenden, bla bla.)

Wenn ihr einen Vertrag habt, dass es niemals nulls in einem Container geben sollte, dann liegt es an euch, sicherzustellen, dass der Vertrag eingehalten wird, wahrscheinlich am angemessensten durch Behauptung. Es hätte wahrscheinlich maximal 10 Codezeilen gedauert. Java macht es Ihnen unglaublich einfach, solche Dinge zu tun. Das JDK kann Ihre Gedanken nicht lesen.

James
quelle
1
Ihr Vorbelegungsargument ist ungültig, da dieses bereits mit der ensureCapacity(int minCapacity)Methode und dem ArrayList(int initialCapacity)Konstruktor in ArrayList integriert ist .
Philipp
7
@Philipp Welche Werte wird es in diesen Raum setzen?
James
Die naheliegende Wahl besteht darin, nullin die vorab zugewiesenen (aber noch nicht verwendeten ) Einträge des ArrayList; aber wir können das zulassen ensureCapacityund doch nicht zulassen, dass andere Funktionen dies settun. Die Gründe, die an anderer Stelle genannt werden, scheinen stärker zu sein.
David K
@DavidK: Es ist sinnvoll zu sagen, dass es möglich sein sollte, seteinen Artikel mit einem beliebigen Wert zu versehen, der von zurückgegeben werden könnte get. Selbst wenn ein normaler Versuch zu geteinem Element, für das Speicherplatz zugewiesen, aber nie geschrieben wurde, eine Ausnahme nulllist1.setOrEraseIfNull(index, list2.getOrReturnNull(index))if (list2.valueSet(index)) list1.set(index, list2.get(index)); else list1.unset(index);
auslösen
1
@DavidK: Der Versuch, einen zugewiesenen, aber noch nicht geschriebenen Eintrag zu lesen, muss entweder null ergeben oder eine Ausnahme auslösen. Es ist einfacher, null zurückzugeben.
Supercat
4

Dies scheint hier eher eine (Software-) philosophische Frage zu sein.

ArrayList as a utility class wurde entwickelt, um in einem breiten Kontext möglicher Anwendungsfälle hilfreich zu sein.

Entgegen Ihrer verborgenen Behauptung, dass von der Annahme von Null als gültigem Wert abgeraten werden sollte, gibt es viele Beispiele, in denen der Nullwert vollkommen legal ist.

Der wichtigste Grund ist, dass nulles sich um das do not knowÄquivalent eines Referenztyps handelt, einschließlich der Framework-Typen. Dies impliziert, dass null in keinem Fall durch eine flüssigere Version des nothingWerts ersetzt werden kann.

Nehmen wir also an, Sie speichern die Ganzzahlen 1, 3, 7 in Ihrer Arrayliste am entsprechenden Index: Aufgrund einiger Berechnungen möchten Sie das Element am Index 5 abrufen. Ihr Array sollte also den Wert "no value saved" zurückgeben. Dies kann erreicht werden, indem null oder ein NullObject zurückgegeben wird . In den meisten Fällen ist die Rückgabe des eingebauten Nullwerts ausreichend aussagekräftig. Nach dem Aufruf einer Methode, die null zurückgeben kann, und der Verwendung ihres Rückgabewerts ist eine Überprüfung des zurückgegebenen Werts gegen null im modernen Code durchaus üblich.

Mare Infinitus
quelle
4

Die Aussage

File f = null;

ist gültig und nützlich (ich glaube nicht, dass ich erklären muss, warum). Es ist ebenfalls nützlich, eine Sammlung von Dateien zu haben, von denen einige null sein können.

List<File> files = new ArrayList<File>();
// use my collection of files
// ....
// not using this one anymore:
files.set(3, null);

Die Nützlichkeit von Sammlungen, die Nullobjekte enthalten können, ergibt sich direkt aus der Nützlichkeit von Objekten, die Null sein können. Es ist wirklich so einfach.

x-code
quelle
2

Es ist einfacher, alles zu akzeptieren, als restriktiv zu sein und dann zu versuchen, Ihr Design nachträglich zu öffnen.

Was wäre zum Beispiel, wenn oracle / sun nur NonNullableArrayList zur Verfügung stellen würde, aber Sie möchten Ihrer Liste eine Null hinzufügen können. Wie würdest du es machen? Sie müssten wahrscheinlich ein ganz anderes Objekt erstellen, Sie könnten die NonNullableArrayList nicht erweitern. Wenn Sie stattdessen eine ArrayList haben, die alles akzeptiert, können Sie sie problemlos erweitern und das Add überschreiben, bei dem keine Nullwerte akzeptiert werden.

NiteRain
quelle
2
Nicht einverstanden Zu viel zuzulassen ist schwieriger zu korrigieren, wenn das Fehlverhalten weit verbreitet ist. Wenn Sprachentwickler zu einem späteren Zeitpunkt Nullen zuließen, würde dies bestehende Programme nicht beschädigen, aber das Gegenteil ist nicht der Fall.
Andres F.
2
Aber ich stimme zu. Es geht darum, die Funktionalität zu maximieren. Sie können eine Liste verwenden, die Nullen akzeptiert, auch wenn Sie diese nicht benötigen. Sie können keine Liste verwenden, die Nullen ablehnt, wenn Sie Nullen benötigen.
Florian F
-1

Nützlichkeit von null?

Ganz besonders, wenn Sie eine Liste mit Listen verwenden, um eine 2D-Platte des realen Lebens mit verschiedenen Positionen zu modellieren . Die Hälfte dieser Positionen kann leer sein (in zufälligen Koordinaten), während die ausgefüllten keine einfache Ganzzahl oder Zeichenfolge darstellen, sondern durch ein komplexes Objekt dargestellt werden. Wenn Sie die Positionsdaten behalten möchten, müssen Sie die leeren Stellen mit Null füllen, damit Ihre list.get (x) .get (y)führt nicht zu bösen Überraschungen. Um den Null-Ausnahmen entgegenzuwirken, können Sie nach Null suchen (sehr beliebt) oder ein Optional verwenden (was ich in diesem Fall nützlich finde). Die Alternative wäre, die leeren Stellen mit "Junk" -Objekten zu füllen, die auf der Straße zu allerlei Unordnung führen können. Wenn Ihre Nullprüfung fehlschlägt oder irgendwo vergessen wird, werden Sie von Java darüber informiert. Andererseits kann ein "Junk" -Platzhalterobjekt, das nicht richtig überprüft wird, unbemerkt bleiben.

Nanokörper
quelle