J'ai travaillé avec le nouveau type facultatif dans Java 8 , et j'ai rencontré ce qui semble être une opération courante qui n'est pas prise en charge fonctionnellement: un "orElseOptional"
Considérez le modèle suivant:
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);
}
Il existe de nombreuses formes de ce modèle, mais cela revient à vouloir un "orElse" sur un optionnel qui prend une fonction produisant un nouveau optionnel, appelé uniquement si l'actuel n'existe pas.
Son implémentation ressemblerait à ceci:
public Optional<T> orElse(Supplier<Optional<? extends T>> otherSupplier) {
return value != null ? this : other.get();
}
Je suis curieux de savoir s'il y a une raison pour laquelle une telle méthode n'existe pas, si j'utilise simplement Optionnel de manière non intentionnelle, et quelles autres façons les gens ont trouvées pour traiter ce cas.
Je dois dire que je pense que les solutions impliquant des classes / méthodes utilitaires personnalisées ne sont pas élégantes car les personnes travaillant avec mon code ne sauront pas nécessairement qu'elles existent.
De plus, si quelqu'un le sait, une telle méthode sera-t-elle incluse dans JDK 9, et où puis-je proposer une telle méthode? Cela me semble être une omission assez flagrante de l'API.
orElseGet()
pour ce dont OP a besoin, mais il ne génère pas une belle syntaxe en cascade.Réponses:
Cela fait partie du JDK 9 sous la forme de
or
, qui prend unSupplier<Optional<T>>
. Votre exemple serait alors:Pour plus de détails, consultez le Javadoc ou ce post que j'ai écrit.
la source
ifPresent
. Mais de toute façon, je pense que le nomifPresent
n'est pas bon de toute façon. Pour toutes les autres méthodes ne portant pas « d' autre » dans le nom (commemap
,filter
,flatMap
), il est sous - entendu qu'ils ne font rien si aucune valeur est présent, alors pourquoiifPresent
...Optional<T> perform(Consumer<T> c)
méthode pour permettre le chaînageperform(x).orElseDo(y)
(orElseDo
comme alternative à votre propositionifEmpty
, pour être cohérentelse
dans le nom de toute méthode qui pourrait faire quelque chose pour les valeurs absentes). Vous pouvez imiter celaperform
dans Java 9 viastream().peek(x).findFirst()
bien que ce soit un abus de l'API et il n'y a toujours aucun moyen d'exécuter unRunnable
sans spécifier unConsumer
en même temps…L'approche «essayer les services» la plus propre étant donné l'API actuelle serait:
L'aspect important n'est pas la chaîne (constante) d'opérations que vous devez écrire une seule fois mais la facilité avec laquelle il est d'ajouter un autre service (ou de modifier la liste des services est générale). Ici, ajouter ou supprimer un single
()->serviceX(args)
suffit.En raison de l'évaluation paresseuse des flux, aucun service ne sera appelé si un service précédent a renvoyé une valeur non vide
Optional
.la source
.map(Optional::get)
avec.findFirst()
rendra plus facile la "lecture", par exemple.filter(Optional::isPresent).findFirst().map(Optional::get)
peut être "lu" comme "trouver le premier élément dans le flux pour lequel Optional :: isPresent est vrai et l'aplatir ensuite en appliquant Optional :: get"?Ce n'est pas joli, mais cela fonctionnera:
.map(func).orElseGet(sup)
est un modèle assez pratique à utiliser avecOptional
. Cela signifie "Si celaOptional
contient de la valeurv
, donnez-moifunc(v)
, sinon donnez-moisup.get()
".Dans ce cas, nous appelons
serviceA(args)
et obtenons un fichierOptional<Result>
. Si celaOptional
contient une valeurv
, nous voulons obtenirOptional.of(v)
, mais si elle est vide, nous voulons obtenirserviceB(args)
. Rincer-répéter avec plus d'alternatives.D'autres utilisations de ce modèle sont
.map(Stream::of).orElseGet(Stream::empty)
.map(Collections::singleton).orElseGet(Collections::emptySet)
la source
() -> {}
ne renvoie pas de fichierOptional
. Qu'est-ce que vous essayez d'accomplir?or(Supplier<Optional<T>>)
Java 9.map()
sur un videOptional
produira un videOptional
.C'est peut-être ce que vous recherchez: obtenez de la valeur à partir de l'un ou l'autre facultatif
Sinon, vous voudrez peut-être jeter un coup d'œil à
Optional.orElseGet
. Voici un exemple de ce que je pense que vous recherchez:la source
ofNullable
est la chose la plus cool que j'ai jamais vue.En supposant que vous soyez toujours sur JDK8, il existe plusieurs options.
Option n ° 1: créez votre propre méthode d'aide
Par exemple:
Pour que vous puissiez faire:
Option 2: utiliser une bibliothèque
Par exemple, l'option facultative de google guava prend en charge une
or()
opération correcte (tout comme JDK9), par exemple:(Où chacun des services revient
com.google.common.base.Optional
, plutôt quejava.util.Optional
).la source
Optional<T>.or(Supplier<Optional<T>>)
dans la documentation Guava. Avez-vous un lien pour cela?Cela ressemble à un bon ajustement pour la correspondance de modèles et une interface Option plus traditionnelle avec des implémentations Some et None (telles que celles de Javaslang , FunctionalJava ) ou une implémentation paresseuse Maybe dans cyclops-react Je suis l'auteur de cette bibliothèque.
Avec cyclops-react, vous pouvez également utiliser la correspondance de motifs structurels sur les types JDK. Pour Optionnel, vous pouvez faire correspondre les cas présents et absents via le modèle de visiteur . ça ressemblerait à quelque chose comme ça -
la source