Recientemente leí sobre esto y vi a personas que usaban esta clase, pero en casi todos los casos, el uso también null
habría funcionado, si no de manera más intuitiva. ¿Alguien puede dar un ejemplo concreto donde Optional
se lograría algo que null
no se pudo o de una manera mucho más limpia? Lo único que se me ocurre es usarlo con Maps
que no acepte null
claves, pero incluso eso se podría hacer con un "mapeo" lateral del valor nulo. ¿Alguien puede proporcionarme un argumento más convincente? Gracias.
89
Respuestas:
Miembro del equipo de guayaba aquí.
Probablemente la mayor desventaja
null
es que no es obvio lo que debería significar en un contexto dado: no tiene un nombre ilustrativo. No siempre es obvio quenull
significa "sin valor para este parámetro"; diablos, como valor de retorno, a veces significa "error", o incluso "éxito" (!!), o simplemente "la respuesta correcta no es nada".Optional
es con frecuencia el concepto al que se refiere cuando convierte una variable en anulable, pero no siempre. Cuando no lo sea, le recomendamos que escriba su propia clase, similar aOptional
pero con un esquema de nomenclatura diferente, para dejar en claro lo que realmente quiere decir.Pero yo diría que la mayor ventaja de
Optional
no es la legibilidad: la ventaja es que es a prueba de idiotas. Te obliga a pensar activamente en el caso ausente si quieres que tu programa se compile, ya que tienes que desenvolver activamenteOptional
y abordar ese caso. Null hace que sea inquietantemente fácil simplemente olvidar cosas, y aunque FindBugs ayuda, no creo que aborde el problema tan bien. Esto es especialmente relevante cuando devuelve valores que pueden estar "presentes" o no. Es mucho más probable que usted (y otros) olviden queother.method(a, b)
podría devolver unnull
valor de lo que es probable que olvide quea
podría sernull
cuando esté implementandoother.method
. RegresandoOptional
hace imposible que las personas que llaman olviden ese caso, ya que tienen que desenvolver el objeto ellos mismos.Por estas razones, le recomendamos que utilice
Optional
como tipo de retorno para sus métodos, pero no necesariamente en los argumentos de su método.(Por cierto, esto se basa totalmente en la discusión aquí ).
fuente
Map
regresanull
si una clave no está asignada, pero recuerde que si lo hacemap.put(key, null)
,map.containsKey(key)
regresarátrue
peromap.get(key)
regresaránull
.Optional
puede ser útil para aclarar la distinción entre el caso "asignado explícitamente a nulo" y el caso "no presente en el mapa". Concedo queOptional
se puede abusar de eso , pero aún no estoy convencido de que el caso que describe sea un abuso.Optional<T>
es ese valor "encontrado, pero no válido"? O más precisamente,Optional<T>
es una forma de decorar cualquier tipoT
con un valor adicional "encontrado, pero no válido", creando un nuevo tipo combinando dos tipos existentes. Si tiene cien clases, puede resultar complicado tener que crear un valor "encontrado, pero no válido" para cada una, peroOptional<T>
puede funcionar fácilmente para todas.Realmente se parece al
Maybe
patrón Monad de Haskell.Debería leer lo siguiente, Wikipedia Monad (programación funcional) :
Y lea De Opcional a Mónada con guayaba en el Blog de Kerflyn, que trata sobre el Opcional de la guayaba utilizada como mónada:
Editar: Con Java8, hay un Opcional incorporado que tiene operadores monádicos como
flatMap
. Este ha sido un tema controvertido pero finalmente se ha implementado.Ver http://www.nurkiewicz.com/2013/08/optional-in-java-8-cheat-sheet.html
El
flatMap
operador es esencial para permitir operaciones monádicas y permite encadenar fácilmente llamadas que devuelven resultados opcionales.Piénselo, si usara el
map
operador 5 veces terminaría con unOptional<Optional<Optional<Optional<Optional<String>>>>>
, mientras que usarloflatMap
le daríaOptional<String>
Desde Java8, prefiero no usar el Opcional de Guava, que es menos poderoso.
fuente
Una buena razón para usarlo es que hace que sus valores nulos sean muy significativos. En lugar de devolver un nulo que podría significar muchas cosas (como error, falla, vacío, etc.), puede poner un 'nombre' a su nulo. Mira este ejemplo:
definamos un POJO básico:
}
Ahora hagamos uso de este sencillo POJO:
Ahora evitemos el uso de nulo y hagamos nuestras comprobaciones con Opcional, por lo que es significativo
por lo tanto, al final, es una forma de hacer que los nulos sean significativos y menos ambiguos.
fuente
La ventaja más importante de Opcional es que agrega más detalles al contrato entre el implementador y el llamador de una función. Por esta razón, es útil tanto para los parámetros como para el tipo de retorno.
Si hace que la convención tenga siempre
Optional
para posibles objetos nulos, agrega más aclaraciones a casos como:Optional<Integer> maxPrime(Optional<Integer> from, Optional<Integer> to)
El contrato aquí especifica claramente que existe la posibilidad de que un resultado no se devuelva, pero también muestra que funcionará con
from
yto
como ausente.Optional<Integer> maxPrime(Optional<Integer> from, Integer to)
El contrato especifica que from es opcional, por lo que un valor ausente puede tener un significado especial como comenzar desde 2. Puedo esperar que un valor nulo para el
to
parámetro arroje una excepción.Entonces, lo bueno de usar Opcional es que el contrato se volvió tanto descriptivo (similar a la
@NotNull
anotación) como formal, ya que debe escribir código.get()
para hacer frenteOptional
.fuente