Holen Sie sich Wert aus dem einen oder anderen Optional

Lesezeit: 5 Minuten

Benutzer-Avatar
Feuermurmel

ich habe zwei java.util.Optional Instanzen und ich möchte eine bekommen Optional das entweder:

  • Hat den Wert des ersten Optional, wenn es einen Wert hat.
  • Hat den Wert des zweiten Optional, wenn es einen Wert hat.
  • Ist leer von weder Optional hat einen Wert.

Gibt es einen einfachen Weg, das zu tun, dh gibt es bereits eine API, um das zu tun?

Die folgenden Ausdrücke werden das tun, aber ich muss die erste Option zweimal erwähnen:

firstOptional.isPresent() ? firstOptional : secondOptional

Das ist genau das, was com.google.common.base.Optional.or() tut, aber diese Methode ist in der API von Java 8 nicht vorhanden.


Die akzeptierte Antwort von aiobe listet einige alternative Ansätze auf, um diese Auslassung des zu überwinden Optional API genau dort, wo ein solcher Wert berechnet werden muss (was meine Frage beantwortet). Ich habe mich jetzt dafür entschieden, meiner Codebasis eine Hilfsfunktion hinzuzufügen:

public static <T> Optional<T> or(Optional<T> a, Optional<T> b) {
    if (a.isPresent())
        return a;
    else
        return b;
}

  • Wenn Sie sich für die Verwendung einer Utility-Funktion entscheiden, würde ich die Verwendung von a empfehlen Supplier<Optional<T>> für den zweiten Parameter, um das Kurzschließen zu unterstützen, wenn der erste vorhanden ist.

    – r0estir0bbe

    25. April 2017 um 12:22 Uhr

  • @r0estir0bbe Das wäre definitiv eine Option. Ich denke, beide Argumente waren in dem Fall, in dem ich das ursprünglich brauchte, sehr billig zu berechnen. Wenn es nach mir ginge, würde ich Haskell schreiben, wo ich nicht darüber nachdenken müsste. 🙂

    – Feuermurmel

    26. April 2017 um 7:33 Uhr

Benutzer-Avatar
aiobe

Java 9 und höher:

firstOptional.or(() -> secondOptional);

Java 8 und darunter

Wenn Sie die Erwähnung vermeiden möchten firstOptional zweimal, müssten Sie wahrscheinlich mit so etwas wie gehen

firstOptional.map(Optional::of).orElse(secondOptional);

oder

Optional.ofNullable(firstOptional.orElse(secondOptional.orElse(null)));

Aber die lesbarste Variante ist wohl einfach zu machen

Optional<...> opt = firstOptional.isPresent()  ? firstOptional
                  : secondOptional.isPresent() ? secondOptional
                  : Optional.empty();

Wenn jemand über diese Frage stolpert, aber eine hat aufführen von optionalen Optionen würde ich so etwas vorschlagen

Optional<...> opt = optionals.stream()
                             .filter(Optional::isPresent)
                             .findFirst()
                             .orElse(Optional.empty());

  • Gibt Ihr drittes Beispiel nicht ein Optional> zurück, da findFirst auf einem Stream> arbeitet? Sie wollen stream().filter(Optional::isPresent).map(o -> o.get()).findFirst()

    – everett1992

    17. Juni 2015 um 16:34 Uhr


  • Erwähnenswert finde ich, dass das Java 8 Äquivalent zum Java 9 Optional.or ist firstOptional.map(Optional::of).orElseGet(()->secondOptional). Es wird nur ausgewertet secondOptional wenn firstOptional ist leer. Verhalten in Analogie zum Logischen ||.

    – wuerg

    19. Dezember 2017 um 18:08 Uhr

Benutzer-Avatar
Erik Gillespie

BEARBEITEN: Ich dachte total, du würdest Guaven verwenden Optional ursprünglich. Ich habe meine Antwort aktualisiert, um sowohl die Guava- als auch die Java 8-Syntax für ihre jeweiligen bereitzustellen Optional Klassen.

Java 8 Optional

Sie können es wie folgt verkürzen:

firstOptional.orElse(secondOptional.orElse(EMPTY_VALUE))

Ich bin mir nicht sicher, was Sie in Ihrem dritten Aufzählungszeichen mit “leer” gemeint haben. Wenn Sie null meinten, dann wird dies den Zweck erfüllen:

firstOptional.orElse(secondOptional.orElse(null))

orElse() ist eine Methode auf Optional Dadurch wird der Wert zurückgegeben, falls vorhanden, andernfalls wird der Wert zurückgegeben, den Sie als Argument für angegeben haben orElse().

Guave Optional

Sie können es wie folgt verkürzen:

firstOptional.or(secondOptional.or(EMPTY_VALUE))

Ich bin mir nicht sicher, was Sie in Ihrem dritten Aufzählungszeichen mit “leer” gemeint haben. Wenn Sie null meinten, dann wird dies den Zweck erfüllen:

firstOptional.or(secondOptional.orNull())

or() ist eine Methode auf Optional Dadurch wird der Wert zurückgegeben, falls vorhanden, andernfalls wird der Wert zurückgegeben, den Sie als Argument für angegeben haben or().

  • Welche Art von optionalen Optionen verwenden Sie? docs.oracle.com/javase/8/docs/api/index.html?java/util/… hat diese Methode nicht

    – Streikkufen

    6. Juli 2014 um 20:31 Uhr

  • *facepalm* Ich dachte fälschlicherweise, dass das OP Guaven verwendet Optional statt Java 8. Ich habe meine Antwort aktualisiert, um die Syntax für beide anzuzeigen.

    – Erik Gillespie

    6. Juli 2014 um 20:34 Uhr


  • Mit “leer” meine ich Optional.empty(). Ich möchte nutzen können ifPresent() auf dem resultierenden optional.

    – Feuermurmel

    7. Juli 2014 um 7:44 Uhr

  • Für das Java 8-Beispiel wird dadurch das Optional entpackt, sodass nur noch ein T übrig bleibt.

    – Matt Klein

    13. April 2017 um 15:52 Uhr

Benutzer-Avatar
Jamaikanisch

Ich hatte ein paar Begegnungen mit einem Problem, das möglicherweise mit JDK 9 gelöst wurde Optional::or und konnte nicht, weil wir JDK 8 verwenden. Schließlich habe ich eine util-Klasse mit dieser Methode hinzugefügt:

@SafeVarargs
public static <T> Optional<T> firstPresent(final Supplier<Optional<T>>... optionals) {
    return Stream.of(optionals)
            .map(Supplier::get)
            .filter(Optional::isPresent)
            .findFirst()
            .orElse(Optional.empty());
}

Jetzt können Sie dieser Methode eine beliebige Anzahl von Optionen zuweisen, die wie folgt träge ausgewertet werden:

    final Optional<String> username = OptionalUtil.firstPresent(
            () -> findNameInUserData(user.getBasicData()),
            () -> findNameInUserAddress(user.getAddress()),
            () -> findDefaultUsername());

Jetzt, findNameInUserAddress wird nur gerufen, wenn findNameInUserData kehrt leer zurück. findDefaultUsername wird nur angerufen wenn beides findNameInUserData und findNameInUserAddress leer zurückgeben usw.

Warum nicht einfach (Supplier Wrapper kann einfach hinzugefügt werden):

    @SafeVarargs
    public static <T> Optional<T> firstPresent(Optional<T>... optionals) {
        return Stream.of(optionals)
                .flatMap(Optional::stream)
                .findFirst();
    }

?

Ich weiß, dass diese Frage alt ist, aber warum verwenden Sie in solchen Fällen nicht einfach etwas Bewährtes wie das Muster der Verantwortungskette? Es ist für Fälle wie Ihren gemacht/entworfen. Und als Zusatznutzen lassen sich ganz einfach weitere Services zur Liste hinzufügen.

Hier ist ein Link, der das Muster beschreibt: https://sourcemaking.com/design_patterns/chain_of_responsibility

  • Wie trifft dies auf meine Frage zu, bei der es darum ging, zwei zu kombinieren Optional<> Instanzen? Können Sie ein Beispiel geben, wie eine Implementierung nach diesem Muster aussehen würde?

    – Feuermurmel

    24. Oktober 2017 um 16:21 Uhr

  • Wie trifft dies auf meine Frage zu, bei der es darum ging, zwei zu kombinieren Optional<> Instanzen? Können Sie ein Beispiel geben, wie eine Implementierung nach diesem Muster aussehen würde?

    – Feuermurmel

    24. Oktober 2017 um 16:21 Uhr

1085250cookie-checkHolen Sie sich Wert aus dem einen oder anderen Optional

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy