@AlexisC. Votre lien concerne la carte et la flatMap de Stream, et non facultatif.
Eran
1
@Eran Cela n'a pas d'importance, si vous comprenez comment fonctionne map / flatMap, que ce soit pour un Stream ou non, c'est la même chose pour un Optional. Si l'op a compris comment cela fonctionne pour un Stream, alors il ne devrait pas poser cette question. Le concept est le même.
Alexis C.
2
@AlexisC. Pas vraiment. Le flatMap en option a peu en commun avec le flatMap de Stream.
Eran
1
@Eran Je parle de la différence conceptuelle entre une map et une flatMap, je ne fais pas de correspondance un-à-un entre Stream#flatMapet Optional#flatMap.
Alexis C.
Réponses:
166
À utiliser mapsi la fonction renvoie l'objet dont vous avez besoin ou flatMapsi la fonction renvoie un Optional. Par exemple:
publicstaticvoid main(String[] args){Optional<String> s =Optional.of("input");System.out.println(s.map(Test::getOutput));System.out.println(s.flatMap(Test::getOutputOpt));}staticString getOutput(String input){return input ==null?null:"output for "+ input;}staticOptional<String> getOutputOpt(String input){return input ==null?Optional.empty():Optional.of("output for "+ input);}
Les deux instructions d'impression impriment la même chose.
Question: appellerait [flat]Mapjamais la fonction de cartographie avec un input == null? Je crois comprendre que les Optionalcoupes de tri s'il est absent - le [JavaDoc] ( docs.oracle.com/javase/8/docs/api/java/util/… ) semble le confirmer - « Si une valeur est présente, appliquez. . ".
@DiegoMartinoia Optional.of(null)est un Exception. Optional.ofNullable(null) == Optional.empty().
Boris the Spider
1
@BoristheSpider oui, vous avez raison. J'essayais de répondre à votre question mais je pense que je l'ai rendue encore plus floue: conceptuellement, Optional.ofNullable (null) ne devrait PAS être vide, mais en pratique, il est considéré comme, et donc map / flatmap ne s'exécute pas.
Diego Martinoia
1
Je pense que l'entrée ne devrait jamais être nulle dans getOutputOpt ou getOutput
DanyalBurke
55
Ils prennent tous deux une fonction du type de l'option à quelque chose.
map()applique la fonction " tel quel " sur l'option que vous avez:
Que se passe-t-il si votre fonction est une fonction de T -> Optional<U>?
Votre résultat est maintenant un Optional<Optional<U>>!
C'est de cela qu'il flatMap()s'agit: si votre fonction retourne déjà un Optional, flatMap()est un peu plus intelligente et ne la double pas, retourne Optional<U>.
C'est la composition de deux idiomes fonctionnels: mapet flatten.
Remarque: - ci-dessous se trouve l'illustration de la fonction map et flatmap, sinon Facultatif est principalement conçu pour être utilisé comme type de retour uniquement.
Comme vous le savez peut-être déjà, Facultatif est un type de conteneur qui peut ou non contenir un seul objet, il peut donc être utilisé partout où vous prévoyez une valeur nulle (vous ne verrez peut-être jamais NPE si vous utilisez Facultatif correctement). Par exemple, si vous avez une méthode qui attend un objet person qui peut être nullable, vous pouvez écrire la méthode quelque chose comme ceci:
void doSome(Optional<Person> person){/*and here you want to retrieve some property phone out of person
you may write something like this:
*/Optional<String> phone = person.map((p)->p.getPhone());
phone.ifPresent((ph)->dial(ph));}classPerson{privateString phone;//setter, getters}
Ici, vous avez renvoyé un type String qui est automatiquement enveloppé dans un type facultatif.
Si la classe de personne ressemblait à ceci, le téléphone est également facultatif
Dans ce cas, l'appel de la fonction map encapsulera la valeur retournée dans Optional et produira quelque chose comme:
Optional<Optional<String>>//And you may want Optional<String> instead, here comes flatMapvoid doSome(Optional<Person> person){Optional<String> phone = person.flatMap((p)->p.getPhone());
phone.ifPresent((ph)->dial(ph));}
PS; N'appelez jamais la méthode get (si vous en avez besoin) sur un Optional sans le vérifier avec isPresent () sauf si vous ne pouvez pas vivre sans NullPointerExceptions.
Je pense que cet exemple est susceptible de détourner l'attention de la nature de votre réponse parce que votre classe Personfait un mauvais usage Optional. Il est contre l'intention de l'API d'utiliser Optionalsur des membres comme celui-ci - voir mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/…
8bitjunkie
@ 8bitjunkie Merci d'avoir souligné cela, cela diffère de l'option de Scala ..
SandeepGodara
6
Ce qui m'a aidé, c'est un regard sur le code source des deux fonctions.
Map - encapsule le résultat dans une option.
public<U>Optional<U> map(Function<?super T,?extends U> mapper){Objects.requireNonNull(mapper);if(!isPresent())return empty();else{returnOptional.ofNullable(mapper.apply(value));//<--- wraps in an optional}}
Qu'entendez-vous par flatMap"renvoie l'objet" brut ""? flatMaprenvoie également l'objet mappé «enveloppé» dans un fichier Optional. La différence est que dans le cas de flatMap, la fonction mapper enveloppe l'objet mappé dans Optionaltandis que maplui-même enveloppe l'objet Optional.
Derek Mahar
@DerekMahar a supprimé le mien, inutile de le re-publier, car vous avez bien édité votre commentaire.
maxxyme
3
Optional.map():
Prend chaque élément et si la valeur existe, elle est passée à la fonction:
Maintenant ajouté a l'une des trois valeurs suivantes: trueou falseencapsulé dans un facultatif , s'il optionalValueétait présent, ou un facultatif vide dans le cas contraire.
Si vous n'avez pas besoin de traiter le résultat que vous pouvez simplement utiliser ifPresent(), il n'a pas de valeur de retour:
optionalValue.ifPresent(results::add);
Optional.flatMap():
Fonctionne de manière similaire à la même méthode de flux. Aplatit le flux de flux. A la différence que si la valeur est présentée, elle est appliquée à la fonction. Sinon, un optionnel vide est renvoyé.
Vous pouvez l'utiliser pour composer des appels de fonctions de valeur facultatives.
Supposons que nous ayons des méthodes:
publicstaticOptional<Double> inverse(Double x){return x ==0?Optional.empty():Optional.of(1/ x);}publicstaticOptional<Double> squareRoot(Double x){return x <0?Optional.empty():Optional.of(Math.sqrt(x));}
Ensuite, vous pouvez calculer la racine carrée de l'inverse, comme:
Optional<Double> result = inverse(-4.0).flatMap(MyMath::squareRoot);
ou, si vous préférez:
Optional<Double> result =Optional.of(-4.0).flatMap(MyMath::inverse).flatMap(MyMath::squareRoot);
Si le inverse()ou les squareRoot()retours Optional.empty(), le résultat est vide.
Cela ne compile pas. Vos deux expressions renvoient un <Double> facultatif plutôt que le double auquel vous affectez le résultat.
JL_SO
@JL_SO vous avez raison. Parce que inverse a le Optional<Double>type comme type de retour.
nazar_art
3
D'accord. Vous n'avez besoin d'utiliser 'flatMap' que lorsque vous faites face à des options imbriquées . Voici l'exemple.
publicclassPerson{privateOptional<Car> optionalCar;publicOptional<Car> getOptionalCar(){return optionalCar;}}publicclassCar{privateOptional<Insurance> optionalInsurance;publicOptional<Insurance> getOptionalInsurance(){return optionalInsurance;}}publicclassInsurance{privateString name;publicString getName(){return name;}}publicclassTest{// map cannot deal with nested OptionalspublicOptional<String> getCarInsuranceName(Person person){return person.getOptionalCar().map(Car::getOptionalInsurance)// ① leads to a Optional<Optional<Insurance>.map(Insurance::getName);// ②}}
Comme Stream, Optional # map renverra une valeur encapsulée par un Optional. C'est pourquoi nous obtenons une option imbriquée - Optional<Optional<Insurance>. Et à ②, nous voulons la cartographier comme une instance d'assurance, c'est ainsi que la tragédie s'est produite. La racine est des options imbriquées. Si nous pouvons obtenir la valeur fondamentale indépendamment des coquilles, nous y arriverons. C'est ce que fait flatMap.
Stream#flatMap
etOptional#flatMap
.Réponses:
À utiliser
map
si la fonction renvoie l'objet dont vous avez besoin ouflatMap
si la fonction renvoie unOptional
. Par exemple:Les deux instructions d'impression impriment la même chose.
la source
[flat]Map
jamais la fonction de cartographie avec uninput == null
? Je crois comprendre que lesOptional
coupes de tri s'il est absent - le [JavaDoc] ( docs.oracle.com/javase/8/docs/api/java/util/… ) semble le confirmer - « Si une valeur est présente, appliquez. . ".Optional.of(null)
est unException
.Optional.ofNullable(null) == Optional.empty()
.Ils prennent tous deux une fonction du type de l'option à quelque chose.
map()
applique la fonction " tel quel " sur l'option que vous avez:Que se passe-t-il si votre fonction est une fonction de
T -> Optional<U>
?Votre résultat est maintenant un
Optional<Optional<U>>
!C'est de cela qu'il
flatMap()
s'agit: si votre fonction retourne déjà unOptional
,flatMap()
est un peu plus intelligente et ne la double pas, retourneOptional<U>
.C'est la composition de deux idiomes fonctionnels:
map
etflatten
.la source
Remarque: - ci-dessous se trouve l'illustration de la fonction map et flatmap, sinon Facultatif est principalement conçu pour être utilisé comme type de retour uniquement.
Comme vous le savez peut-être déjà, Facultatif est un type de conteneur qui peut ou non contenir un seul objet, il peut donc être utilisé partout où vous prévoyez une valeur nulle (vous ne verrez peut-être jamais NPE si vous utilisez Facultatif correctement). Par exemple, si vous avez une méthode qui attend un objet person qui peut être nullable, vous pouvez écrire la méthode quelque chose comme ceci:
Ici, vous avez renvoyé un type String qui est automatiquement enveloppé dans un type facultatif.
Si la classe de personne ressemblait à ceci, le téléphone est également facultatif
Dans ce cas, l'appel de la fonction map encapsulera la valeur retournée dans Optional et produira quelque chose comme:
PS; N'appelez jamais la méthode get (si vous en avez besoin) sur un Optional sans le vérifier avec isPresent () sauf si vous ne pouvez pas vivre sans NullPointerExceptions.
la source
Person
fait un mauvais usageOptional
. Il est contre l'intention de l'API d'utiliserOptional
sur des membres comme celui-ci - voir mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/…Ce qui m'a aidé, c'est un regard sur le code source des deux fonctions.
Map - encapsule le résultat dans une option.
flatMap - renvoie l'objet 'brut'
la source
flatMap
"renvoie l'objet" brut ""?flatMap
renvoie également l'objet mappé «enveloppé» dans un fichierOptional
. La différence est que dans le cas deflatMap
, la fonction mapper enveloppe l'objet mappé dansOptional
tandis quemap
lui-même enveloppe l'objetOptional
.Optional.map()
:Prend chaque élément et si la valeur existe, elle est passée à la fonction:
Maintenant ajouté a l'une des trois valeurs suivantes:
true
oufalse
encapsulé dans un facultatif , s'iloptionalValue
était présent, ou un facultatif vide dans le cas contraire.Si vous n'avez pas besoin de traiter le résultat que vous pouvez simplement utiliser
ifPresent()
, il n'a pas de valeur de retour:Optional.flatMap()
:Fonctionne de manière similaire à la même méthode de flux. Aplatit le flux de flux. A la différence que si la valeur est présentée, elle est appliquée à la fonction. Sinon, un optionnel vide est renvoyé.
Vous pouvez l'utiliser pour composer des appels de fonctions de valeur facultatives.
Supposons que nous ayons des méthodes:
Ensuite, vous pouvez calculer la racine carrée de l'inverse, comme:
ou, si vous préférez:
Si le
inverse()
ou lessquareRoot()
retoursOptional.empty()
, le résultat est vide.la source
Optional<Double>
type comme type de retour.D'accord. Vous n'avez besoin d'utiliser 'flatMap' que lorsque vous faites face à des options imbriquées . Voici l'exemple.
Comme Stream, Optional # map renverra une valeur encapsulée par un Optional. C'est pourquoi nous obtenons une option imbriquée -
Optional<Optional<Insurance>
. Et à ②, nous voulons la cartographier comme une instance d'assurance, c'est ainsi que la tragédie s'est produite. La racine est des options imbriquées. Si nous pouvons obtenir la valeur fondamentale indépendamment des coquilles, nous y arriverons. C'est ce que fait flatMap.En fin de compte, je vous recommande vivement Java 8 In Action si vous souhaitez étudier Java8 systématiquement.
la source