J'ai deux instances Java.util.Optional
Et je veux obtenir un Optional
qui soit:
Existe-t-il un moyen simple de le faire, c'est-à-dire qu'il existe déjà une API pour le faire?
Les expressions suivantes feront cela, mais je dois mentionner deux fois la première option:
firstOptional.isPresent() ? firstOptional : secondOptional
C'est exactement ce que fait com.google.common.base.Optional.or()
, mais cette méthode n'est pas présente dans l'API de Java 8).
La réponse acceptée par aioobe énumère quelques approches alternatives pour surmonter cette omission de l'API Optional
là où une telle valeur doit être calculée (ce qui répond à ma question). J'ai maintenant choisi d'ajouter une fonction utilitaire à ma base de code:
public static <T> Optional<T> or(Optional<T> a, Optional<T> b) {
if (a.isPresent())
return a;
else
return b;
}
Mise à jour: À partir de Java 9 ( changeset 12885 ) vous pouvez faire
firstOptional.or(() -> secondOptional);
Pour Java 8, lisez la suite ...
Si vous voulez éviter de mentionner firstOptional
deux fois, vous devrez probablement choisir quelque chose comme
firstOptional.map(Optional::of).orElse(secondOptional);
ou
Optional.ofNullable(firstOptional.orElse(secondOptional.orElse(null)));
Mais la variante la plus lisible est probablement de simplement faire
Optional<...> opt = firstOptional.isPresent() ? firstOptional
: secondOptional.isPresent() ? secondOptional
: Optional.empty();
Si quelqu'un tombe sur cette question mais a une liste d'options, je suggérerais quelque chose comme
Optional<...> opt = optionals.stream()
.filter(Optional::isPresent)
.findFirst()
.orElse(Optional.empty());
EDIT: Je pensais totalement que vous utilisiez le Optional
de Guava à l'origine. J'ai mis à jour ma réponse pour fournir à la fois Guava et Java 8 syntaxe pour leurs classes Optional
respectives.
Java 8 en option
Vous pouvez le raccourcir jusqu'à ceci:
firstOptional.orElse(secondOptional.orElse(EMPTY_VALUE))
Je ne sais pas ce que vous vouliez dire dans votre troisième puce par "vide". Si vous vouliez dire null, cela fera l'affaire:
firstOptional.orElse(secondOptional.orElse(null))
orElse()
est une méthode sur Optional
qui retournera la valeur si elle est présente, sinon elle renverra la valeur que vous avez fournie comme argument à orElse()
.
Goyave en option
Vous pouvez le raccourcir jusqu'à ceci:
firstOptional.or(secondOptional.or(EMPTY_VALUE))
Je ne sais pas ce que vous vouliez dire dans votre troisième puce par "vide". Si vous vouliez dire null, cela fera l'affaire:
firstOptional.or(secondOptional.orNull())
or()
est une méthode sur Optional
qui retournera la valeur si elle est présente, sinon elle renverra la valeur que vous avez fournie comme argument à or()
.
J'ai rencontré quelques fois un problème qui aurait pu être résolu avec JDK 9 Optional::or
et n'a pas pu parce que nous utilisons JDK 8. Enfin, j'ai ajouté une classe util avec cette méthode:
@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());
}
Vous pouvez maintenant fournir n'importe quel nombre d'options à cette méthode et elles seront évaluées paresseusement comme suit:
final Optional<String> username = OptionalUtil.firstPresent(
() -> findNameInUserData(user.getBasicData()),
() -> findNameInUserAddress(user.getAddress()),
() -> findDefaultUsername());
Maintenant, findNameInUserAddress
ne sera appelé que si findNameInUserData
retourne vide. findDefaultUsername
ne sera appelé que si findNameInUserData
et findNameInUserAddress
renvoient vide etc.