@AlexisC. Su enlace es sobre el mapa de Stream y flatMap, no Opcional.
Eran
1
@Eran Eso no importa, si comprende cómo funciona map / flatMap, ya sea para un Stream o no, es lo mismo para un Opcional. Si el operador entendió cómo funciona para un Stream, entonces no debería hacer esta pregunta. El concepto es el mismo.
Alexis C.
2
@AlexisC. Realmente no. FlatMap de Opcional tiene poco en común con flatMap de Stream.
Eran
1
@Eran Estoy hablando de la diferencia conceptual entre un mapa y un FlatMap, no estoy haciendo una correspondencia uno a uno entre Stream#flatMapy Optional#flatMap.
Alexis C.
Respuestas:
166
Use mapsi la función devuelve el objeto que necesita o flatMapsi la función devuelve un Optional. Por ejemplo:
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);}
Pregunta: ¿ [flat]Mapalguna vez llamaría a la función de mapeo con un input == null? Tengo entendido que Optionalsortcuts si está ausente: el [JavaDoc] ( docs.oracle.com/javase/8/docs/api/java/util/… ) parece respaldar esto: " Si hay un valor presente, aplique ... . ".
@DiegoMartinoia Optional.of(null)es un Exception. Optional.ofNullable(null) == Optional.empty().
Boris the Spider
1
@BoristheSpider sí, tienes razón. Intenté responder a su pregunta, pero creo que lo hice aún más confuso: conceptualmente, Opcional. De Anulable (nulo) NO debe estar vacío, pero en la práctica se considera que está, y por lo tanto, map / flatmap no se ejecutan.
Diego Martinoia
1
Creo que la entrada nunca debería ser nula en getOutputOpt o getOutput
DanyalBurke
55
Ambos toman una función del tipo de opcional a algo.
map()aplica la función " tal cual " en el opcional que tiene:
¿Qué sucede si su función es una función de T -> Optional<U>?
Su resultado es ahora un Optional<Optional<U>>!
De eso flatMap()se trata: si su función ya devuelve un Optional, flatMap()es un poco más inteligente y no lo envuelve dos veces, regresando Optional<U>.
Es la composición de dos modismos funcionales: mapy flatten.
Nota: a continuación se muestra la ilustración del mapa y la función de mapa plano; de lo contrario, Opcional está diseñado principalmente para usarse solo como un tipo de retorno.
Como ya sabrá, Opcional es un tipo de contenedor que puede contener o no un solo objeto, por lo que se puede usar siempre que anticipe un valor nulo (es posible que nunca vea NPE si usa Opcional correctamente). Por ejemplo, si tiene un método que espera que un objeto persona sea anulable, puede escribir el método de la siguiente manera:
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}
Aquí ha devuelto un tipo de cadena que se ajusta automáticamente en un tipo opcional.
Si la clase de persona se ve así, es decir, el teléfono también es opcional
En este caso, invocar la función de mapa envolverá el valor devuelto en Opcional y producirá algo como:
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));}
PD; Nunca llame al método get (si es necesario) en un Opcional sin verificarlo con isPresent () a menos que no pueda vivir sin NullPointerExceptions.
Creo que es probable que este ejemplo distraiga la naturaleza de su respuesta porque su clase Personestá haciendo un mal uso Optional. Es en contra de la intención de la API usar Optionalen miembros como este: ver mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/…
8bitjunkie
@ 8bitjunkie Gracias por señalarlo, difiere de la opción de Scala ...
SandeepGodara
6
Lo que me ayudó fue mirar el código fuente de las dos funciones.
Mapa : ajusta el resultado en un Opcional.
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é quiere decir con flatMap"devuelve el objeto 'crudo'"? flatMaptambién devuelve el objeto mapeado "envuelto" en un Optional. La diferencia es que, en el caso de flatMap, la función de mapeador envuelve el objeto mapeado Optionalmientras que el mapmismo lo envuelve Optional.
Derek Mahar
@DerekMahar eliminó el mío, no es necesario volver a publicarlo, porque ha editado su comentario correctamente.
maxxyme
3
Optional.map():
Toma todos los elementos y si el valor existe, se pasa a la función:
Ahora agregado tiene uno de tres valores: trueo falseenvuelto en un Opcional , si optionalValueestaba presente, o un Opcional vacío de lo contrario.
Si no necesita procesar el resultado, simplemente puede usarlo ifPresent(), no tiene valor de retorno:
optionalValue.ifPresent(results::add);
Optional.flatMap():
Funciona de manera similar al mismo método de secuencias. Aplana la corriente de corrientes. Con la diferencia de que si se presenta el valor, se aplica a la función. De lo contrario, se devuelve un opcional vacío.
Puede usarlo para componer llamadas de funciones de valor opcionales.
Supongamos que tenemos métodos:
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));}
Luego puedes calcular la raíz cuadrada de la inversa, como:
Optional<Double> result = inverse(-4.0).flatMap(MyMath::squareRoot);
o, si lo prefieres:
Optional<Double> result =Optional.of(-4.0).flatMap(MyMath::inverse).flatMap(MyMath::squareRoot);
Si el inverse()o el squareRoot()devuelve Optional.empty(), el resultado está vacío.
Esto no se compila. Ambas expresiones devuelven un Opcional <Doble> en lugar del Doble al que está asignando el resultado.
JL_SO
@JL_SO tienes razón. Porque inverso tiene Optional<Double>tipo como tipo de retorno.
nazar_art
3
Bueno. Usted sólo tendrá que utilizar 'flatMap' cuando estás frente a Opcionales anidados . Aquí está el ejemplo.
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);// ②}}
Al igual que Stream, el mapa opcional # devolverá un valor envuelto por un opcional. Es por eso que obtenemos un Opcional anidado - Optional<Optional<Insurance>. Y en ②, queremos mapearlo como una instancia de Seguros, así es como sucedió la tragedia. La raíz está anidada. Opcionales. Si podemos obtener el valor central independientemente de los shells, lo haremos. Eso es lo que hace flatMap.
Stream#flatMap
yOptional#flatMap
.Respuestas:
Use
map
si la función devuelve el objeto que necesita oflatMap
si la función devuelve unOptional
. Por ejemplo:Ambas declaraciones impresas imprimen lo mismo.
fuente
[flat]Map
alguna vez llamaría a la función de mapeo con uninput == null
? Tengo entendido queOptional
sortcuts si está ausente: el [JavaDoc] ( docs.oracle.com/javase/8/docs/api/java/util/… ) parece respaldar esto: " Si hay un valor presente, aplique ... . ".Optional.of(null)
es unException
.Optional.ofNullable(null) == Optional.empty()
.Ambos toman una función del tipo de opcional a algo.
map()
aplica la función " tal cual " en el opcional que tiene:¿Qué sucede si su función es una función de
T -> Optional<U>
?Su resultado es ahora un
Optional<Optional<U>>
!De eso
flatMap()
se trata: si su función ya devuelve unOptional
,flatMap()
es un poco más inteligente y no lo envuelve dos veces, regresandoOptional<U>
.Es la composición de dos modismos funcionales:
map
yflatten
.fuente
Nota: a continuación se muestra la ilustración del mapa y la función de mapa plano; de lo contrario, Opcional está diseñado principalmente para usarse solo como un tipo de retorno.
Como ya sabrá, Opcional es un tipo de contenedor que puede contener o no un solo objeto, por lo que se puede usar siempre que anticipe un valor nulo (es posible que nunca vea NPE si usa Opcional correctamente). Por ejemplo, si tiene un método que espera que un objeto persona sea anulable, puede escribir el método de la siguiente manera:
Aquí ha devuelto un tipo de cadena que se ajusta automáticamente en un tipo opcional.
Si la clase de persona se ve así, es decir, el teléfono también es opcional
En este caso, invocar la función de mapa envolverá el valor devuelto en Opcional y producirá algo como:
PD; Nunca llame al método get (si es necesario) en un Opcional sin verificarlo con isPresent () a menos que no pueda vivir sin NullPointerExceptions.
fuente
Person
está haciendo un mal usoOptional
. Es en contra de la intención de la API usarOptional
en miembros como este: ver mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/…Lo que me ayudó fue mirar el código fuente de las dos funciones.
Mapa : ajusta el resultado en un Opcional.
flatMap : devuelve el objeto 'sin procesar'
fuente
flatMap
"devuelve el objeto 'crudo'"?flatMap
también devuelve el objeto mapeado "envuelto" en unOptional
. La diferencia es que, en el caso deflatMap
, la función de mapeador envuelve el objeto mapeadoOptional
mientras que elmap
mismo lo envuelveOptional
.Optional.map()
:Toma todos los elementos y si el valor existe, se pasa a la función:
Ahora agregado tiene uno de tres valores:
true
ofalse
envuelto en un Opcional , sioptionalValue
estaba presente, o un Opcional vacío de lo contrario.Si no necesita procesar el resultado, simplemente puede usarlo
ifPresent()
, no tiene valor de retorno:Optional.flatMap()
:Funciona de manera similar al mismo método de secuencias. Aplana la corriente de corrientes. Con la diferencia de que si se presenta el valor, se aplica a la función. De lo contrario, se devuelve un opcional vacío.
Puede usarlo para componer llamadas de funciones de valor opcionales.
Supongamos que tenemos métodos:
Luego puedes calcular la raíz cuadrada de la inversa, como:
o, si lo prefieres:
Si el
inverse()
o elsquareRoot()
devuelveOptional.empty()
, el resultado está vacío.fuente
Optional<Double>
tipo como tipo de retorno.Bueno. Usted sólo tendrá que utilizar 'flatMap' cuando estás frente a Opcionales anidados . Aquí está el ejemplo.
Al igual que Stream, el mapa opcional # devolverá un valor envuelto por un opcional. Es por eso que obtenemos un Opcional anidado -
Optional<Optional<Insurance>
. Y en ②, queremos mapearlo como una instancia de Seguros, así es como sucedió la tragedia. La raíz está anidada. Opcionales. Si podemos obtener el valor central independientemente de los shells, lo haremos. Eso es lo que hace flatMap.Al final, te recomiendo encarecidamente el Java 8 en acción si deseas estudiar Java8 sistemáticamente.
fuente