Mit Java 9 wurden neue Factory-Methoden für das List
, Set
und eingeführtMap
Schnittstellen. Mit diesen Methoden kann ein Map-Objekt schnell mit Werten in einer Zeile instanziiert werden. Nun, wenn wir überlegen:
Map<Integer, String> map1 = new HashMap<Integer, String>(Map.of(1, "value1", 2, "value2", 3, "value3"));
map1.put(4, null);
Dies ist ausnahmslos zulässig, wenn wir Folgendes tun:
Map<Integer, String> map2 = Map.of(1, "value1", 2, "value2", 3, "value3", 4, null );
Es wirft:
Exception in thread "main" java.lang.NullPointerException
at java.base/java.util.Objects.requireNonNull(Objects.java:221)
..
Ich kann nicht bekommen, verstehen warum null im zweiten Fall nicht erlaubt ist.
Ich weiß, dass HashMap sowohl Null als Schlüssel als auch Wert annehmen kann, aber warum wurde dies im Fall von Map.of eingeschränkt?
Das gleiche passiert im Fall von java.util.Set.of("v1", "v2", null)
und java.util.List.of("v1", "v2", null)
.
Antworten:
Wie andere betonten, erlaubt der
Map
Vertrag die Ablehnung von Nullen ...... und die Sammelfabriken (nicht nur auf Karten) machen davon Gebrauch .
Aber wieso?
Das Zulassen
null
von Sammlungen wird mittlerweile als Entwurfsfehler angesehen. Dies hat verschiedene Gründe. Eine gute ist die Benutzerfreundlichkeit, bei der der bekannteste Problemlöser istMap::get
. Wenn es zurückkehrtnull
, ist unklar, ob der Schlüssel fehlt oder der Wert warnull
. Im Allgemeinen sind Sammlungen, die garantiertnull
kostenlos sind, einfacher zu verwenden. In Bezug auf die Implementierung erfordern sie auch weniger spezielles Gehäuse, wodurch der Code einfacher zu warten und leistungsfähiger ist.Sie können Stuart Marks zuhören, der es in diesem Vortrag erklärt, aber JEP 269 (derjenige, der die Factory-Methoden eingeführt hat) fasst es auch zusammen:
Da dies
HashMap
bereits in freier Wildbahn war, als dies langsam entdeckt wurde, war es zu spät, es zu ändern, ohne den vorhandenen Code zu beschädigen, aber die neuesten Implementierungen dieser Schnittstellen (z. B.ConcurrentHashMap
) lassen dies nichtnull
mehr zu und die neuen Sammlungen für die Factory-Methoden sind keine Ausnahme.(Ich dachte, ein anderer Grund war die explizite Verwendung
null
Werten als wahrscheinlicher Implementierungsfehler angesehen wurde, aber ich habe das falsch verstanden. Das war dabei, Schlüssel zu duplizieren, die ebenfalls illegal sind.)Das Nichtzulassen
null
hatte also einen technischen Grund, wurde aber auch durchgeführt, um die Robustheit des Codes mithilfe der erstellten Sammlungen zu verbessern.quelle
get
, wird null zurückgegeben. Was bedeutet das? Es hat eine Zuordnung von null oder ist es nicht vorhanden? Auch der Umgang mit Nullschlüsseln ist immer anders, Sie können keinen Hashcode berechnen ... Wenn Sie ihn zunächst nicht zulassen, wird die Arbeit einfacherget
Rückkehrnull
. Aber anstattMap
mit einer neuen Methode zu erweitern, die eine zurückgibt, wurdeOptional
diese geringfügige Einschränkung eingeführt, die absolut nichts löst, da sich jeder Code, der sich mit einemMap
Still befasst, nicht darauf verlassen kann, nichtnull
zurück zu kommen. In der Zwischenzeit können Personen, dieMap
irgendwo eine Konstante übergeben möchten, dienull
Werte mit gutem Grund zulässt , diese sehr praktische Funktion nicht nutzen .Optional
-s einzige Aufgabe ist es, eine explizitenull
Behandlung zu vermeiden. Wenn Ihr Vorschlag in die Praxis umgesetzt würde, müsste jeder Aufruf einerOptional
Rückgabemethode einenull
Überprüfung durchführen und sich trotzdem mit dem leeren Fall befassen. Das ist ein absurder Vorschlag. In Bezug auf Laufzeitüberraschungen wissen Sie, dassMap
Implementierungen NPEs frei auslösen können, wenn Sie versuchen,put
einennull
Schlüssel oder Wert zu ermitteln, oder? (ConcurrentHashMap
tut das.) Wie sind Sie bisher damit umgegangen?Genau - a
HashMap
darf null speichern, nicht dieMap
von den statischen Factory-Methoden zurückgegebenen. Nicht alle Karten sind gleich.Soweit ich weiß, ist es in erster Linie ein Fehler, Nullen in den
HashMap
as-Schlüsseln zuzulassen. Neuere Sammlungen verbieten diese Möglichkeit zunächst.Denken Sie an den Fall, wenn Sie einen Eintrag in Ihrem haben
HashMap
, der einen bestimmten Schlüssel und Wert == null hat. Sie bekommen, es kehrt zurücknull
. Was bedeutet das? Es hat eine Zuordnung vonnull
oder ist es nicht vorhanden?Gleiches gilt für einen
Key
- Hashcode von einem solchen Nullschlüssel, der ständig speziell behandelt werden muss. Zu Beginn das Verbot von Nullen - machen Sie dies einfacher.quelle
Während HashMap Nullwerte zulässt,
Map.of
verwendet a keinHashMap
und löst eine Ausnahme aus, wenn einer entweder als Schlüssel oder als Wert verwendet wird, wie dokumentiert :quelle
Das Zulassen von Nullen in Karten war ein Fehler. Wir können es jetzt sehen , aber ich denke, es war nicht klar, wann
HashMap
es eingeführt wurde.NullpointerException
ist der häufigste Fehler im Produktionscode.Ich würde sagen, dass das JDK in die Richtung geht, Entwicklern bei der Bekämpfung der NPE-Pest zu helfen. Einige Beispiele:
Optional
Collectors.toMap(keyMapper, valueMapper)
erlaubt weder derkeyMapper
noch dervalueMapper
Funktion, einennull
Wert zurückzugebenStream.findFirst()
undStream.findAny()
wirf NPE, wenn der gefundene Wert istnull
Ich denke also, dass das Nichtzulassen
null
der neuen unveränderlichen JDK9-Sammlungen (und Karten) in die gleiche Richtung geht.quelle
Der Hauptunterschied ist: Wenn Sie Ihre eigene Karte auf die "Option 1" Weise erstellen ... dann sagen Sie implizit : "Ich möchte volle Freiheit in dem haben, was ich tue."
Wenn Sie also entscheiden, dass Ihre Karte einen Nullschlüssel oder -wert haben soll (möglicherweise aus den hier aufgeführten Gründen ), können Sie dies tun.
Aber „Option 2“ geht es um eine Bequemlichkeit Sache - wahrscheinlich gedacht für Konstanten verwendet werden. Und die Leute hinter Java haben einfach entschieden: "Wenn Sie diese praktischen Methoden verwenden, ist die resultierende Karte nullfrei."
Unter Berücksichtigung von null Werte bedeuten , dass
if (map.contains(key))
ist nicht dasselbe wie
if (map.get(key) != null)
Das könnte manchmal ein Problem sein. Genauer gesagt: Es ist etwas, an das man sich erinnern muss, wenn man sich mit genau diesem Kartenobjekt befasst.
Und nur ein anekdotischer Hinweis, warum dies ein vernünftiger Ansatz zu sein scheint: Unser Team hat selbst ähnliche Convenience-Methoden implementiert. Und raten Sie mal: Ohne etwas über Pläne für zukünftige Java-Standardmethoden zu wissen, machen unsere Methoden genau dasselbe: Sie geben eine unveränderliche Kopie der eingehenden Daten zurück. und sie werden angezeigt, wenn Sie Nullelemente bereitstellen. Wir sind sogar so streng, dass wir uns auch beschweren , wenn Sie leere Listen / Karten / ... einreichen.
quelle
Die Dokumentation sagt nicht, warum
null
nicht erlaubt ist:Meiner Meinung nach werden die
Map.of()
undMap.ofEntries()
statischen Factory-Methoden, die eine Konstante erzeugen, meist von einem Entwickler des Kompilierungstyps gebildet. Was ist dann der Grund, anull
als Schlüssel oder Wert beizubehalten?Während dies
Map#put
normalerweise verwendet wird, wird zur Laufzeit eine Karte gefüllt, in dernull
Schlüssel / Werte auftreten können.quelle
Map.of()
eine Instanz zurück,ImmutableCollections.MapN
die eine Tabelle verwendet,null
die ihr Ende angeben muss. Dokument dieser Klasse: "Es gibt eine einzelne Array" -Tabelle ", die * verschachtelte Schlüssel und Werte enthält ... Die Tabellengröße muss gerade sein. Sie muss außerdem streng größer sein als die Größe (die Anzahl der Schlüssel-Wert-Paare in die Karte), so dass immer mindestens ein Nullschlüssel vorhanden ist "Warum es so gemacht wird, anstatt nur ein int zu verwenden, um die Größe zu halten, weiß ich nicht; Vielleicht Hashing ... (der Code ist ein bisschen beängstigend )Map
mit Schlüssel / Wert-Paaren, die beispielsweise für Felder in einer Datenbank bestimmt sind, profitiert von Nullwerten. Ich denke, es ist zurück zu einemNULL
Platzhalterobjekt für diese. IMHO ist der Grund kleinlich oder einfach eine Überreaktion auf die Anti-Null-Mentalität.Meiner Meinung nach ist Nicht-Nullfähigkeit für Schlüssel sinnvoll, aber nicht für Werte.
Map
Schnittstelle wird zu einem schwachen Vertrag. Sie können dem Verhalten nicht vertrauen, ohne sich die Implementierung anzusehen. Dies setzt voraus, dass Sie Zugriff darauf haben. Java11Map.of()
erlaubt zwar keine NullwerteHashMap
, aber beide implementieren denselbenMap
Vertrag - wie kommt es?Map.of()
als Konstrukt für solche Strukturen unbrauchbar.quelle
Nicht alle Karten erlauben Null als Schlüssel
Der in der
docs of Map
.quelle