Ich füge diese zweite Antwort basierend auf einer vorgeschlagenen Bearbeitung durch den Benutzer srborlongan zu meiner anderen Antwort hinzu . Ich denke, die vorgeschlagene Technik war interessant, aber sie war nicht wirklich als Bearbeitung für meine Antwort geeignet. Andere stimmten zu und die vorgeschlagene Änderung wurde abgelehnt. (Ich war nicht einer der Wähler.) Die Technik hat jedoch ihre Berechtigung. Es wäre am besten gewesen, wenn Srborlongan seine eigene Antwort gepostet hätte. Dies ist noch nicht geschehen, und ich wollte nicht, dass die Technik im Nebel des von StackOverflow abgelehnten Bearbeitungsverlaufs verloren geht. Deshalb habe ich beschlossen, sie selbst als separate Antwort anzuzeigen.
Grundsätzlich besteht die Technik darin, einige der Optional
Methoden auf clevere Weise zu verwenden, um zu vermeiden, dass ein ternärer Operator ( ? :
) oder eine if / else-Anweisung verwendet werden muss.
Mein Inline-Beispiel würde folgendermaßen umgeschrieben:
Optional<Other> result =
things.stream()
.map(this::resolve)
.flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))
.findFirst();
Ein Beispiel, das eine Hilfsmethode verwendet, wird folgendermaßen umgeschrieben:
/**
* Turns an Optional<T> into a Stream<T> of length zero or one depending upon
* whether a value is present.
*/
static <T> Stream<T> streamopt(Optional<T> opt) {
return opt.map(Stream::of)
.orElseGet(Stream::empty);
}
Optional<Other> result =
things.stream()
.flatMap(t -> streamopt(resolve(t)))
.findFirst();
KOMMENTAR
Vergleichen wir die Originalversion mit der modifizierten Version direkt:
// original
.flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
// modified
.flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))
Das Original ist ein unkomplizierter, wenn auch fachmännischer Ansatz: Wir bekommen einen Optional<Other>
; Wenn es einen Wert hat, geben wir einen Stream zurück, der diesen Wert enthält, und wenn es keinen Wert hat, geben wir einen leeren Stream zurück. Ziemlich einfach und leicht zu erklären.
Die Modifikation ist clever und hat den Vorteil, dass sie Bedingungen vermeidet. (Ich weiß, dass einige Leute den ternären Operator nicht mögen. Wenn er missbraucht wird, kann dies tatsächlich dazu führen, dass Code schwer zu verstehen ist.) Manchmal können die Dinge jedoch zu klug sein. Der geänderte Code beginnt ebenfalls mit einem Optional<Other>
. Dann ruft es auf, Optional.map
was wie folgt definiert ist:
Wenn ein Wert vorhanden ist, wenden Sie die bereitgestellte Zuordnungsfunktion darauf an. Wenn das Ergebnis nicht null ist, geben Sie eine Option zurück, die das Ergebnis beschreibt. Andernfalls geben Sie eine leere Option zurück.
Der map(Stream::of)
Anruf gibt eine zurück Optional<Stream<Other>>
. Wenn in der Eingabe Optional ein Wert vorhanden war, enthält die zurückgegebene Option einen Stream, der das einzelne Ergebnis Other enthält. Wenn der Wert jedoch nicht vorhanden war, ist das Ergebnis leer. Optional.
Als nächstes gibt der Aufruf von orElseGet(Stream::empty)
einen Wert vom Typ zurück Stream<Other>
. Wenn sein Eingabewert vorhanden ist, erhält er den Wert, der das Einzelelement ist Stream<Other>
. Andernfalls (wenn der Eingabewert fehlt) wird ein Leerzeichen zurückgegeben Stream<Other>
. Das Ergebnis ist also korrekt, genauso wie der ursprüngliche Bedingungscode.
In den Kommentaren zu meiner Antwort bezüglich der abgelehnten Bearbeitung hatte ich diese Technik als "prägnanter, aber auch dunkler" beschrieben. Ich stehe dazu. Ich brauchte eine Weile, um herauszufinden, was es tat, und ich brauchte auch eine Weile, um die obige Beschreibung dessen, was es tat, aufzuschreiben. Die Schlüssel-Subtilität ist die Transformation von Optional<Other>
nach Optional<Stream<Other>>
. Sobald Sie dies verstanden haben, macht es Sinn, aber es war mir nicht klar.
Ich werde jedoch anerkennen, dass Dinge, die anfangs dunkel sind, mit der Zeit idiomatisch werden können. Es könnte sein, dass diese Technik der beste Weg in der Praxis ist, zumindest bis sie Optional.stream
hinzugefügt wird (falls dies jemals der Fall sein sollte).
UPDATE: Optional.stream
wurde zu JDK 9 hinzugefügt.
.flatMap(Optional::toStream)
, die sich auf Ihre Version bezieht, wenn sie existiert hat. Sie sehen tatsächlich, was los ist.