Voici ce que j'ai jusqu'à présent:
Optional<Foo> firstChoice = firstChoice();
Optional<Foo> secondChoice = secondChoice();
return Optional.ofNullable(firstChoice.orElse(secondChoice.orElse(null)));
Cela me semble hideux et inutile. Si firstChoice est présent, je calcule inutilement secondChoice.
Il y a aussi une version plus efficace:
Optional<Foo> firstChoice = firstChoice();
if(firstChoice.isPresent()) {
return firstChoice;
} else {
return secondChoice();
}
Ici, je ne peux pas enchaîner une fonction de mappage sans dupliquer le mappeur ou déclarer une autre variable locale. Tout cela rend le code plus compliqué que le problème à résoudre.
Je préférerais beaucoup écrire ceci:
return firstChoice().alternatively(secondChoice());
Cependant, Facultatif :: de toute évidence, cela n'existe pas. Maintenant quoi?
Essaye ça:
firstChoice().map(Optional::of)
.orElseGet(this::secondChoice);
La méthode de la carte vous donne un Optional<Optional<Foo>>
. Ensuite, la méthode orElseGet
l'aplatit pour la transformer en Optional<Foo>
. La méthode secondChoice
ne sera évaluée que si firstChoice()
renvoie l'élément facultatif vide.
Vous pouvez simplement remplacer cela par,
Optional<Foo> firstChoice = firstChoice();
return firstChoice.isPresent()? firstChoice : secondChoice();
Le code ci-dessus n'appellera que si firstChoice.isPresent () est false.
Mais vous devez être prêt à appeler les deux fonctions pour obtenir le résultat souhaité. Il n'y a pas d'autre moyen d'échapper à la vérification.
Voici la généralisation de la solution @marstran pour n’importe quel nombre d’options:
@SafeVarargs
public static <T> Optional<T> selectOptional(Supplier<Optional<T>>... optionals) {
return Arrays.stream(optionals)
.reduce((s1, s2) -> () -> s1.get().map(Optional::of).orElseGet(s2))
.orElse(Optional::empty).get();
}
Tester:
public static Optional<String> first() {
System.out.println("foo called");
return Optional.empty();
}
public static Optional<String> second() {
System.out.println("bar called");
return Optional.of("bar");
}
public static Optional<String> third() {
System.out.println("baz called");
return Optional.of("baz");
}
public static void main(String[] args) {
System.out.println(selectOptional(() -> first(), () -> second(), () -> third()));
}
Sortie:
foo called
bar called
Optional[bar]
Peut-être quelque chose comme ça:
Optional<String> finalChoice = Optional.ofNullable(firstChoice()
.orElseGet(() -> secondChoice()
.orElseGet(() -> null)));
J'étais assez frustré par le fait que cela ne soit pas supporté par Java 8, que je sois revenu aux options de goyave qui ont or
:
public abstract Optional<T> or(Optional<? extends T> secondChoice)
Renvoie cette option si elle a une valeur présente; secondChoice sinon.
Calculs différés et nombre arbitraire d'éléments Optional
Stream.<Supplier<Optional<Foo>>>of(
this::firstChoice,
this::secondChoice
).map(
Supplier::get
).filter(
Optional::isPresent
).findFirst(
).orElseGet(
Optional::empty
);