Options de chaînage en Java 8
cherche un moyen de enchaîner les options pour que la première qui est présente soit retournée. Si aucun n'est présent Optional.empty()
doit être retourné.
en supposant que j'ai plusieurs méthodes comme celle-ci:
Optional<String> find1()
j'essaie de les enchaîner:
Optional<String> result = find1().orElse( this::find2 ).orElse( this::find3 );
mais bien sûr cela ne fonctionne pas parce que orElse
attend une valeur et orElseGet
attend un Supplier
.
5 réponses
l'Utilisation d'un Ruisseau:
Stream.of(find1(), find2(), find3())
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();
si vous avez besoin d'évaluer les méthodes find paresseusement, utiliser les fonctions de fournisseur:
Stream.of(this::find1, this::find2, this::find3)
.map(Supplier::get)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();
vous pourriez le faire comme ceci:
Optional<String> resultOpt = Optional.of(find1()
.orElseGet(() -> find2()
.orElseGet(() -> find3()
.orElseThrow(() -> new WhatEverException()))));
bien que je ne suis pas sûr qu'il améliore la lisibilité IMO. La goyave offre un moyen D'enchaîner les optionnels:
import com.google.common.base.Optional;
Optional<String> resultOpt = s.find1().or(s.find2()).or(s.find3());
il pourrait être une autre alternative pour votre problème, mais n'utilise pas la classe optionnelle standard dans le JDK.
si vous voulez conserver l'API standard, vous pouvez écrire une méthode d'utilité simple:
static <T> Optional<T> or(Optional<T> first, Optional<T> second) {
return first.isPresent() ? first : second;
}
et ensuite:
Optional<String> resultOpt = or(s.find1(), or(s.find2(), s.find3()));
si vous avez beaucoup d'options à chains, peut-être qu'il est préférable d'utiliser L'approche Stream comme les autres mentionnés déjà.
inspiré de la réponse de Sauli, il est possible d'utiliser la méthode flatMap()
.
Stream.of(this::find1, this::find2, this::find3)
.map(Supplier::get)
.flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))
.findFirst();
convertir un optionnel en un flux est encombrant. Apparemment, cela va être fixé avec JDK9 . Donc ça pourrait s'écrire comme
Stream.of(this::find1, this::find2, this::find3)
.map(Supplier::get)
.flatMap(Optional::stream)
.findFirst();
mise à jour après la sortie de Java 9
bien que la question originale était sur Java 8, Optional::or
a été introduit en Java 9. Avec elle, le problème pourrait être résolu comme suit:
Optional<String> result = find1()
.or(this::find2)
.or(this::find3);
pour effectuer chaînage optionnel première convertir flux en option en utilisant l'une des deux méthodes
- findAny() ou la méthode findFirst()
- min () et max()
une fois optionnel est obtenu optionnel a deux méthodes d'instance supplémentaires qui sont également présentes dans la classe de flux I. e filter and map(). l'utilisation de ces méthodes et de vérifier sortie d'utiliser ifPresent(Système d'.sortie:: Println)
ex:
Flux s = Stream.de (1,2,3,4);
S. findFirst ().filtre (a)->a+1).ifPresent(System.sortie:: Println)
sortie: 2
peut-être un de
public <T> Optional<? extends T> firstOf(Optional<? extends T> first, @SuppressWarnings("unchecked") Supplier<Optional<? extends T>>... supp) {
if (first.isPresent()) return first;
for (Supplier<Optional <? extends T>> sup : supp) {
Optional<? extends T> opt = sup.get();
if (opt.isPresent()) {
return opt;
}
}
return Optional.empty();
}
public <T> Optional<? extends T> firstOf(Optional<? extends T> first, Stream<Supplier<Optional<? extends T>>> supp) {
if (first.isPresent()) return first;
Stream<Optional<? extends T>> present = supp.map(Supplier::get).filter(Optional::isPresent);
return present.findFirst().orElseGet(Optional::empty);
}
fera l'affaire.
la première itère sur un réseau de fournisseurs. Le premier Optional<>
non vide est retourné. Si nous n'en trouvons pas, nous retournons un Optional
vide .
le second fait la même chose avec un Stream
de Suppliers
qui est traversé, chacun demandé (paresseusement) pour leur valeur, qui est ensuite filtré pour vide Optional
s. La première non vide est retourné, ou si aucune n'existe, un vide.