Warum wirft das ein java.lang.NullPointerException
?
List<String> strings = new ArrayList<>();
strings.add(null);
strings.add("test");
String firstString = strings.stream()
.findFirst() // Exception thrown here
.orElse("StringWhenListIsEmpty");
//.orElse(null); // Changing the `orElse()` to avoid ambiguity
Der erste Punkt in strings
ist null
, was ein vollkommen akzeptabler Wert ist. Darüber hinaus findFirst()
gibt eine Optional , die für noch mehr Sinn macht , findFirst()
zu handhaben zu können null
s.
BEARBEITEN: aktualisiert orElse()
, um weniger mehrdeutig zu sein.
java
java-8
java-stream
optional
Neverendingqs
quelle
quelle
String
hier verwende, was ist, wenn es eine Liste ist, die eine Spalte in der Datenbank darstellt? Der Wert der ersten Zeile für diese Spalte kann seinnull
.null
ist im Allgemeinen ein durchaus akzeptabler Wert in Java. Insbesondere ist es ein gültiges Element für eineArrayList<String>
. Wie bei jedem anderen Wert gibt es jedoch Einschränkungen, was damit gemacht werden kann. "Niemals verwendennull
" ist kein nützlicher Rat, da Sie ihn nicht vermeiden können.findFirst()
Sie bis zu Ihrem Anruf nichts mehr tun möchten.Antworten:
Der Grund dafür ist die Verwendung
Optional<T>
in der Rücksendung. Optional darf nicht enthalten seinnull
. Im Wesentlichen bietet es keine Möglichkeit, Situationen zu unterscheiden, "es ist nicht da" und "es ist da, aber es ist eingestellt aufnull
".Aus diesem Grund verbietet die Dokumentation ausdrücklich die Situation, wenn
null
ausgewählt wird infindFirst()
:quelle
Optional
. Wie auch immer, ich glaube, ich bin fast am Rande des Geschwätzes - wenn die Sprache es nicht unterstützt, unterstützt sie es nicht.boolean
zur Unterscheidung dieser beiden Situationen wäre absolut sinnvoll. Für mich scheint die Verwendung vonOptional<T>
hier eine fragwürdige Wahl zu sein.Iterable
Typ abruft , prüfthasNext()
und den entsprechenden Wert zurückgibt.findFirst
inWie bereits erwähnt , gehen die API-Designer nicht davon aus, dass der Entwickler
null
Werte und fehlende Werte gleich behandeln möchte .Wenn Sie dies dennoch tun möchten, können Sie dies explizit tun, indem Sie die Sequenz anwenden
zum Strom. Das Ergebnis ist in beiden Fällen leer, wenn kein erstes Element vorhanden ist oder wenn das erste Element vorhanden ist
null
. In Ihrem Fall können Sie also verwendenum einen
null
Wert zu erhalten , wenn das erste Element fehlt odernull
.Wenn Sie zwischen diesen Fällen unterscheiden möchten, können Sie das einfach weglassen
flatMap
Schritt :Dies unterscheidet sich nicht wesentlich von Ihrer aktualisierten Frage. Sie müssen nur
"no such element"
mit"StringWhenListIsEmpty"
und"first element is null"
mit ersetzennull
. Aber wenn Sie Bedingungen nicht mögen, können Sie es auch erreichen wie:Nun
firstString
wird es sein,null
wenn ein Element existiert, aber es istnull
und es wird sein,"StringWhenListIsEmpty"
wenn kein Element existiert.quelle
null
entweder für 1) das erste Elementnull
oder 2) keine Elemente in der Liste zurückkehren möchte . Ich habe die Frage aktualisiert, um die Mehrdeutigkeit zu beseitigen.Optional
kann ein zugewiesen werdennull
. DaOptional
es sich um einen "Werttyp" handeln soll, sollte er niemals null sein. Und ein Optional sollte niemals von verglichen werden==
. Der Code kann in Java 10 fehlschlagen :) oder wenn ein Werttyp in Java eingeführt wird.null
und während Instanzen niemals verglichen werden sollten==
, kann die Referenz auf ihrenull
Verwendung getestet werden==
, da dies die einzige Möglichkeit ist, sie zu testennull
. Ich kann nicht sehen, wie ein solcher Übergang zu "nienull
" für vorhandenen Code funktionieren sollte, da selbst der Standardwert für alle Instanzvariablen und Array-Elemente istnull
. Das Snippet ist sicherlich nicht der beste Code, aber es ist auch nicht die Aufgabe,null
s als aktuelle Werte zu behandeln.null
. Da eine solche hypothetische Sprachänderung jedoch dazu führen würde, dass der Compiler hier einen Fehler ausgibt (den Code nicht stillschweigend bricht), kann ich damit leben, dass er möglicherweise für Java 10 angepasst werden müsste. Ich nehme an, dieStream
API wird dies tun sehen dann auch ganz anders aus…Sie können
java.util.Objects.nonNull
die Liste vor dem Suchen filternetwas wie
quelle
firstString
sein,null
wenn der erste Artikel instrings
istnull
.Optional.of
was nicht null sicher ist. Sie könntenmap
zuOptional.ofNullable
und dann verwenden,findFirst
aber Sie werden mit einem Optional von OptionalDer folgende Code wird
findFirst()
durchlimit(1)
und ersetztorElse()
durchreduce()
:limit()
lässt nur 1 Element zu erreichenreduce
. DasBinaryOperator
übergeben anreduce
gibt das 1 Element oder sonst zurück"StringWhenListIsEmpty"
wenn keine Elemente das erreichenreduce
.Das Schöne an dieser Lösung ist, dass sie
Optional
nicht zugewiesen wird und dasBinaryOperator
Lambda nichts zuweisen wird.quelle
Optional soll ein "Wert" -Typ sein. (Lesen Sie das Kleingedruckte in Javadoc :) JVM könnte sogar alle
Optional<Foo>
durch nur ersetzen und alleFoo
Kosten für das Ein- und Auspacken beseitigen. Einnull
Foo bedeutet leerOptional<Foo>
.Es ist möglich, Optional mit einem Nullwert zuzulassen, ohne ein boolesches Flag hinzuzufügen. Fügen Sie einfach ein Sentinel-Objekt hinzu. (könnte sogar gebrauchen
this
als Sentinel verwendet werden; siehe Throwable.cause)Die Entscheidung, dass Optional nicht null umbrechen kann, basiert nicht auf den Laufzeitkosten. Dies war ein äußerst umstrittenes Problem, und Sie müssen die Mailinglisten durchsuchen. Die Entscheidung überzeugt nicht alle.
Da Optional den Nullwert nicht umbrechen kann, werden wir in Fällen wie z
findFirst
. Sie müssen begründet haben, dass Nullwerte sehr selten sind (es wurde sogar in Betracht gezogen, dass Stream Nullwerte sperren sollte), daher ist es bequemer, Ausnahmen für Nullwerte anstatt für leere Streams auszulösen.Eine Problemumgehung besteht darin
null
, z(Sie sagen, dass die Lösung für jedes OOP-Problem darin besteht, einen anderen Typ einzuführen :)
quelle
Box
Typ zu erstellen . DerOptional
Typ selbst kann diesem Zweck dienen. Siehe meine Antwort für ein Beispiel.null
ist ein gültiger Wert wie jeder andere keine besondere Behandlung dafür. (bis