Java Language
Optionnel
Recherche…
Introduction
Optional
est un objet conteneur qui peut ou non contenir une valeur non nulle. Si une valeur est présente, isPresent()
retournera true
et get()
retournera la valeur.
Des méthodes supplémentaires dépendant de la présence de la valeur contenue sont fournies, telles que orElse()
, qui renvoie une valeur par défaut si value not present, et ifPresent()
qui exécute un bloc de code si la valeur est présente.
Syntaxe
- Optional.empty () // Crée une instance facultative vide.
- Facultatif.of (valeur) // Renvoie une option avec la valeur non nulle spécifiée. Une exception NullPointerException sera lancée si la valeur transmise est nulle.
- Facultatif.ofNullable (value) // Renvoie une option avec la valeur spécifiée pouvant être nulle.
Renvoie la valeur par défaut si Facultatif est vide
Ne vous contentez pas d'utiliser Optional.get()
car cela peut NoSuchElementException
. Les méthodes Optional.orElse(T)
et Optional.orElseGet(Supplier<? extends T>)
permettent de fournir une valeur par défaut dans le cas où l'option Facultatif est vide.
String value = "something";
return Optional.ofNullable(value).orElse("defaultValue");
// returns "something"
return Optional.ofNullable(value).orElseGet(() -> getDefaultValue());
// returns "something" (never calls the getDefaultValue() method)
String value = null;
return Optional.ofNullable(value).orElse("defaultValue");
// returns "defaultValue"
return Optional.ofNullable(value).orElseGet(() -> getDefaultValue());
// calls getDefaultValue() and returns its results
La différence cruciale entre orElse
et orElseGet
fait que ce dernier n'est évalué que lorsque le orElseGet
Optional est vide, tandis que l'argument fourni au précédent est évalué même si le paramètre Facultatif n'est pas vide. L' orElse
ne doit donc être utilisé que pour les constantes et jamais pour fournir une valeur basée sur un calcul quelconque.
Carte
Utilisez la méthode map()
de Optional
pour travailler avec des valeurs pouvant être null
sans effectuer de vérifications null
explicites:
(Notez que les opérations map()
et filter()
sont évaluées immédiatement, contrairement à leurs homologues Stream qui ne sont évalués que lors d'une opération de terminal .)
Syntaxe:
public <U> Optional<U> map(Function<? super T,? extends U> mapper)
Exemples de code:
String value = null;
return Optional.ofNullable(value).map(String::toUpperCase).orElse("NONE");
// returns "NONE"
String value = "something";
return Optional.ofNullable(value).map(String::toUpperCase).orElse("NONE");
// returns "SOMETHING"
Etant donné que Optional.map () renvoie une valeur facultative vide lorsque sa fonction de mappage renvoie la valeur null, vous pouvez chaîner plusieurs opérations map () sous forme de déréférencement null-safe. Ceci est également connu sous le nom de chaînage Null-safe .
Prenons l'exemple suivant:
String value = foo.getBar().getBaz().toString();
Tout ce qui getBar
, getBaz
et toString
peut potentiellement lancer une NullPointerException
.
Voici une autre manière d’obtenir la valeur de toString()
utilisant Optional
:
String value = Optional.ofNullable(foo)
.map(Foo::getBar)
.map(Bar::getBaz)
.map(Baz::toString)
.orElse("");
Cela renverra une chaîne vide si l'une des fonctions de mappage retourne null.
Voici un autre exemple, mais légèrement différent. Il imprimera la valeur uniquement si aucune des fonctions de mappage n'a renvoyé la valeur null.
Optional.ofNullable(foo)
.map(Foo::getBar)
.map(Bar::getBaz)
.map(Baz::toString)
.ifPresent(System.out::println);
Lancer une exception, s'il n'y a pas de valeur
Utilisez la méthode orElseThrow()
de Optional
pour obtenir la valeur contenue ou lancer une exception, si elle n'a pas été définie. Ceci est similaire à l'appel de get()
, sauf qu'il permet des types d'exceptions arbitraires. La méthode prend un fournisseur qui doit renvoyer l'exception à lancer.
Dans le premier exemple, la méthode renvoie simplement la valeur contenue:
Optional optional = Optional.of("something");
return optional.orElseThrow(IllegalArgumentException::new);
// returns "something" string
Dans le deuxième exemple, la méthode renvoie une exception car une valeur n'a pas été définie:
Optional optional = Optional.empty();
return optional.orElseThrow(IllegalArgumentException::new);
// throws IllegalArgumentException
Vous pouvez également utiliser la syntaxe lambda si une exception avec un message est nécessaire:
optional.orElseThrow(() -> new IllegalArgumentException("Illegal"));
Filtre
filter()
est utilisé pour indiquer que vous souhaitez la valeur uniquement si elle correspond à votre prédicat.
Pensez-y comme if (!somePredicate(x)) { x = null; }
.
Exemples de code:
String value = null;
Optional.ofNullable(value) // nothing
.filter(x -> x.equals("cool string"))// this is never run since value is null
.isPresent(); // false
String value = "cool string";
Optional.ofNullable(value) // something
.filter(x -> x.equals("cool string"))// this is run and passes
.isPresent(); // true
String value = "hot string";
Optional.ofNullable(value) // something
.filter(x -> x.equals("cool string"))// this is run and fails
.isPresent(); // false
Utilisation de conteneurs facultatifs pour les types de nombres primitifs
OptionalDouble
, OptionalInt
et OptionalLong
fonctionnent comme Optional
, mais sont spécifiquement conçus pour envelopper les types primitifs:
OptionalInt presentInt = OptionalInt.of(value);
OptionalInt absentInt = OptionalInt.empty();
Comme les types numériques ont une valeur, il n'y a pas de traitement spécial pour null. Les conteneurs vides peuvent être vérifiés avec:
presentInt.isPresent(); // Is true.
absentInt.isPresent(); // Is false.
De même, des raccourcis existent pour faciliter la gestion de la valeur:
// Prints the value since it is provided on creation.
presentInt.ifPresent(System.out::println);
// Gives the other value as the original Optional is empty.
int finalValue = absentInt.orElseGet(this::otherValue);
// Will throw a NoSuchElementException.
int nonexistentValue = absentInt.getAsInt();
N'exécutez le code que s'il y a une valeur présente
Optional<String> optionalWithValue = Optional.of("foo");
optionalWithValue.ifPresent(System.out::println);//Prints "foo".
Optional<String> emptyOptional = Optional.empty();
emptyOptional.ifPresent(System.out::println);//Does nothing.
Fournissez une valeur par défaut en utilisant un fournisseur
La méthode orElse
normale prend un Object
, donc vous pourriez vous demander pourquoi il existe une option pour fournir un Supplier
ici (la méthode orElseGet
).
Considérer:
String value = "something";
return Optional.ofNullable(value)
.orElse(getValueThatIsHardToCalculate()); // returns "something"
Il appellerait toujours getValueThatIsHardToCalculate()
même si son résultat n'est pas utilisé car l'option n'est pas vide.
Pour éviter cette pénalité, vous fournissez un fournisseur:
String value = "something";
return Optional.ofNullable(value)
.orElseGet(() -> getValueThatIsHardToCalculate()); // returns "something"
De cette manière, getValueThatIsHardToCalculate()
sera uniquement appelé si le getValueThatIsHardToCalculate()
Optional
est vide.
FlatMap
flatMap
est similaire à map
. La différence est décrite par le javadoc comme suit:
Cette méthode est similaire à
map(Function)
, mais le mappeur fourni est un mappeur dont le résultat est déjàOptional
.flatMap
estflatMap
,flatMap
ne l'enveloppe pas avec unOptional
supplémentaire.
En d'autres termes, lorsque vous enchaînez un appel de méthode qui renvoie un Optional
, l'utilisation de Optional.flatMap
évite de créer des options Optionals
imbriquées.
Par exemple, compte tenu des classes suivantes:
public class Foo {
Optional<Bar> getBar(){
return Optional.of(new Bar());
}
}
public class Bar {
}
Si vous utilisez Optional.map
, vous obtiendrez un Optional
imbriqué; c'est-à-dire Optional<Optional<Bar>>
.
Optional<Optional<Bar>> nestedOptionalBar =
Optional.of(new Foo())
.map(Foo::getBar);
Cependant, si vous utilisez Optional.flatMap
, vous obtiendrez un simple Optional
; c'est-à-dire Optional<Bar>
.
Optional<Bar> optionalBar =
Optional.of(new Foo())
.flatMap(Foo::getBar);