Ich habe mit dem neuen optionalen Typ in Java 8 gearbeitet und bin auf eine allgemeine Operation gestoßen, die funktional nicht unterstützt wird: eine "orElseOptional"
Betrachten Sie das folgende Muster:
Optional<Result> resultFromServiceA = serviceA(args);
if (resultFromServiceA.isPresent) return result;
else {
Optional<Result> resultFromServiceB = serviceB(args);
if (resultFromServiceB.isPresent) return resultFromServiceB;
else return serviceC(args);
}
Es gibt viele Formen dieses Musters, aber es läuft darauf hinaus, ein "orElse" für ein optionales Element zu wollen, das eine Funktion übernimmt, die ein neues optionales Element erzeugt, das nur aufgerufen wird, wenn das aktuelle nicht vorhanden ist.
Die Implementierung würde folgendermaßen aussehen:
public Optional<T> orElse(Supplier<Optional<? extends T>> otherSupplier) {
return value != null ? this : other.get();
}
Ich bin gespannt, ob es einen Grund gibt, warum es eine solche Methode nicht gibt, ob ich Optional nur unbeabsichtigt verwende und welche anderen Möglichkeiten die Leute gefunden haben, um mit diesem Fall umzugehen.
Ich sollte sagen, dass ich denke, dass Lösungen mit benutzerdefinierten Dienstprogrammklassen / -methoden nicht elegant sind, da Leute, die mit meinem Code arbeiten, nicht unbedingt wissen, dass sie existieren.
Wenn jemand weiß, wird eine solche Methode in JDK 9 enthalten sein, und wo könnte ich eine solche Methode vorschlagen? Dies scheint mir eine ziemlich krasse Auslassung der API zu sein.
orElseGet()
für was OP benötigt, nur generiert es keine schöne kaskadierende Syntax.Antworten:
Dies ist Teil von JDK 9 in Form von
or
, das aSupplier<Optional<T>>
. Ihr Beispiel wäre dann:Für Details siehe den Javadoc oder diesen Beitrag, den ich geschrieben habe.
quelle
ifPresent
. Aber ich denke, der NameifPresent
ist sowieso nicht gut. Für alle anderen Methoden nicht „anders“ im Namen tragen (wiemap
,filter
,flatMap
), wird angedeutet , dass sie nichts tun , wenn kein Wert vorhanden ist, so sollte , warumifPresent
...Optional<T> perform(Consumer<T> c)
Methode hinzu, um eine Verkettung zu ermöglichenperform(x).orElseDo(y)
(orElseDo
als Alternative zu Ihrer vorgeschlagenen Methode, um im Namen aller MethodenifEmpty
konsistent zu seinelse
, die möglicherweise etwas für fehlende Werte tun). Sie können diesperform
in Java 9 nachahmen,stream().peek(x).findFirst()
obwohl dies ein Missbrauch der API ist und es immer noch keine Möglichkeit gibt, eine auszuführen,Runnable
ohneConsumer
gleichzeitig eine anzugeben …Der sauberste Ansatz für "Try Services" angesichts der aktuellen API wäre:
Der wichtige Aspekt ist nicht die (konstante) Kette von Operationen, die Sie einmal schreiben müssen, sondern wie einfach es ist, einen anderen Dienst hinzuzufügen (oder die Liste der Dienste zu ändern, ist allgemein). Hier reicht es aus, eine einzelne hinzuzufügen oder zu entfernen
()->serviceX(args)
.Aufgrund der verzögerten Auswertung von Streams wird kein Dienst aufgerufen, wenn ein vorhergehender Dienst einen nicht leeren zurückgegeben hat
Optional
.quelle
.map(Optional::get)
mit.findFirst()
das "Lesen" erleichtert, z. B..filter(Optional::isPresent).findFirst().map(Optional::get)
"Lesen" wie "Finden Sie das erste Element im Stream, für das Optional :: isPresent wahr ist, und reduzieren Sie es dann durch Anwenden von Optional :: get".Es ist nicht schön, aber das wird funktionieren:
.map(func).orElseGet(sup)
ist ein ziemlich praktisches Muster für die Verwendung mitOptional
. Es bedeutet "Wenn diesOptional
Wert enthältv
, gib mirfunc(v)
, sonst gib mirsup.get()
".In diesem Fall rufen wir an
serviceA(args)
und bekommen eineOptional<Result>
. Wenn dasOptional
Wert enthältv
, wollen wir bekommenOptional.of(v)
, aber wenn es leer ist, wollen wir bekommenserviceB(args)
. Spülen-Wiederholen mit mehr Alternativen.Andere Verwendungen dieses Musters sind
.map(Stream::of).orElseGet(Stream::empty)
.map(Collections::singleton).orElseGet(Collections::emptySet)
quelle
() -> {}
gibt kein zurückOptional
. Was versuchst du zu erreichen?or(Supplier<Optional<T>>)
Java 9.map()
auf einem leerenOptional
wird ein leeres erzeugenOptional
.Vielleicht ist es das, wonach Sie suchen: Holen Sie sich den Wert von der einen oder anderen Option
Andernfalls möchten Sie vielleicht einen Blick darauf werfen
Optional.orElseGet
. Hier ist ein Beispiel dafür, was Sie meiner Meinung nach suchen:quelle
ofNullable
ist das Coolste, was ich je gesehen habe.Angenommen, Sie arbeiten noch mit JDK8, gibt es mehrere Optionen.
Option 1: Erstellen Sie Ihre eigene Hilfsmethode
Z.B:
Damit Sie tun können:
Option 2: Verwenden Sie eine Bibliothek
Zum Beispiel unterstützt Google Guavas Optional einen ordnungsgemäßen
or()
Betrieb (genau wie JDK9), z.(Wo jeder der Dienste zurückkehrt
com.google.common.base.Optional
, anstattjava.util.Optional
).quelle
Optional<T>.or(Supplier<Optional<T>>)
in den Guava-Dokumenten gefunden. Hast du einen Link dafür?Dies scheint eine gute Lösung für den Mustervergleich und eine traditionellere Optionsoberfläche mit einigen und keiner Implementierungen (wie die in Javaslang , FunctionalJava ) oder eine faule Vielleicht- Implementierung in Cyclops- React zu sein. Ich bin der Autor dieser Bibliothek.
Mit cyclops reagieren Sie auch strukturelle verwenden können Pattern - Matching auf JDK - Typen. Optional können Sie aktuelle und fehlende Fälle über das Besuchermuster abgleichen . es würde ungefähr so aussehen -
quelle