Después de haber estado utilizando Java 8 ahora durante más de 6 meses, estoy bastante contento con los nuevos cambios de API. Un área en la que aún no confío es cuándo usarla Optional. Parece que me pongo entre querer usarlo en todas partes donde algo pueda estar null, y en ninguna parte.
Parece que hay muchas situaciones en las que podría usarlo, y nunca estoy seguro de si agrega beneficios (legibilidad / seguridad nula) o solo causa una sobrecarga adicional.
Entonces, tengo algunos ejemplos, y estaría interesado en los pensamientos de la comunidad sobre si Optionales beneficioso.
1 - Como un método de devolución de método público cuando el método podría devolver null:
public Optional<Foo> findFoo(String id);2 - Como parámetro de método cuando el parámetro puede ser null:
public Foo doSomething(String id, Optional<Bar> barOptional);3 - Como miembro opcional de un bean:
public class Book {
  private List<Pages> pages;
  private Optional<Index> index;
}4 - En Collections:
En general no pienso:
List<Optional<Foo>>agrega cualquier cosa, especialmente porque se puede usar filter()para eliminar nullvalores, etc., pero ¿hay algún buen uso Optionalen las colecciones?
¿Algún caso que me haya perdido?

Map<Character, String>. Si no hay una sustitución puedo usar esto:Optional.ofNullable(map.get(c)).orElse(String.valueOf(c)). También tenga en cuenta que Opcional fue robado de Guava y tiene una sintaxis mucho mejor:Optional.fromNullable(map.get(c)).or(String.valueOf(c));.filter(Optional::absent)eliminar los "valores nulos"getOrDefault()?Respuestas:
El punto principal de
Optionales proporcionar un medio para que una función devuelva un valor para indicar la ausencia de un valor de retorno. Ver esta discusión . Esto permite que la persona que llama continúe una cadena de llamadas de métodos fluidas.Esto coincide más estrechamente con el caso de uso # 1 en la pregunta del OP. Sin embargo , la ausencia de un valor es una formulación más precisa que nula ya que algo así
IntStream.findFirstnunca podría volver nula.Para el caso de uso # 2 , pasar un argumento opcional a un método, esto podría funcionar, pero es bastante torpe. Supongamos que tiene un método que toma una cadena seguida de una segunda cadena opcional. Aceptar un
Optionalcomo el segundo argumento daría como resultado un código como este:Incluso aceptar nulo es mejor:
Probablemente lo mejor es tener un método sobrecargado que acepte un único argumento de cadena y proporcione un valor predeterminado para el segundo:
Esto tiene limitaciones, pero es mucho mejor que cualquiera de los anteriores.
Los casos de uso n.º 3 y n.º 4 , que tienen un
Optionalcampo de clase o una estructura de datos, se consideran un mal uso de la API. Primero, va en contra del objetivo principal de diseñoOptionalcomo se indica en la parte superior. En segundo lugar, no agrega ningún valor.Hay tres formas de lidiar con la ausencia de un valor en un
Optional: para proporcionar un valor sustituto, para llamar a una función para proporcionar un valor sustituto o para lanzar una excepción. Si está almacenando en un campo, lo haría en el momento de la inicialización o la asignación. Si está agregando valores a una lista, como lo mencionó el OP, tiene la opción adicional de simplemente no agregar el valor, "aplanando" los valores ausentes.Estoy seguro de que alguien podría idear algunos casos artificiales en los que realmente quieran almacenar una
Optionalen un campo o una colección, pero en general, es mejor evitar hacerlo.fuente
Optionalcampo como cuando las cosas se deben hacer o no con la presencia o ausencia de un valor.if(foo == null)internamente sería mejor que simplemente almacenar el campo comooptional. Y no veo por qué llamar explícitamentegetOptionalFoo()internamente es mejor que simplemente almacenar el campo como unOptional. Además, si un campo puede sernully un campo no puede sernull, ¿por qué no comunicarlo al compilador haciéndolosOptionalo noOptional?Optional<>expertos: "no almacenarOptional<>en un campo". Realmente estoy tratando de entender el punto de esta recomendación. Considere un árbol DOM donde un nodo podría tener un padre o no. Parece dentro del caso de uso queNode.getParent()volveríaOptional<Node>. ¿Realmente se espera que almacene unnully ajuste el resultado cada vez? ¿Por qué? ¿Qué me compra esta ineficiencia adicional, aparte de hacer que mi código se vea feo?Optional<Node> getParent() { return Optional.ofNullable(parent); }. ¡Esto parece caro porque asigna unaOptionalcada vez! Pero si la persona que llama lo desempaqueta inmediatamente, el objeto tiene una vida extremadamente corta y nunca sale del espacio edén. Posiblemente incluso podría ser eliminado por el análisis de escape del JIT. La respuesta final es "depende" como siempre, pero el usoOptionalen campos potencialmente aumenta el uso de memoria y ralentiza el recorrido de la estructura de datos. Y finalmente creo que desordenan el código, pero esto es cuestión de gustos.Llego tarde al juego, pero por lo que vale, quiero agregar mis 2 centavos. Van en contra del objetivo de diseño de
Optional, que está bien resumido por la respuesta de Stuart Marks , pero todavía estoy convencido de su validez (obviamente).Usar opcional en todas partes
En general
Escribí una publicación de blog
Optionalcompleta sobre el uso, pero básicamente se reduce a esto:Optionallugar denullLas dos primeras excepciones pueden reducir la sobrecarga percibida de envolver y desenvolver referencias en
Optional. Se eligen de manera que un valor nulo nunca pueda pasar legalmente un límite de una instancia a otra.Tenga en cuenta que esto casi nunca permitirá
Optionals en colecciones que es casi tan malo comonulls. Solo no lo hagas. ;)Con respecto a sus preguntas
Ventajas
Hacer esto reduce la presencia de
nulls en su base de código, aunque no los erradica. Pero ese ni siquiera es el punto principal. Hay otras ventajas importantes:Aclara la intención
El uso
Optionalexpresa claramente que la variable es, bueno, opcional. Cualquier lector de su código o consumidor de su API será derrotado con el hecho de que podría no haber nada allí y que es necesario realizar una verificación antes de acceder al valor.Elimina la incertidumbre
Sin
Optionalel significado de unnullhecho no está claro. Podría ser una representación legal de un estado (verMap.get) o un error de implementación como una inicialización faltante o fallida.Esto cambia dramáticamente con el uso persistente de
Optional. Aquí, ya la aparición denullsignifica la presencia de un error. (Porque si se permitiera que faltara el valor,Optionalse habría utilizado un.) Esto hace que la depuración de una excepción de puntero nulo sea mucho más fácil ya que la pregunta sobre el significado de estonullya está respondida.Más cheques nulos
Ahora que nada puede ser
nullmás, esto puede hacerse cumplir en todas partes. Ya sea con anotaciones, aserciones o comprobaciones simples, nunca tendrá que pensar si este argumento o ese tipo de retorno pueden ser nulos. No puede!Desventajas
Por supuesto, no hay bala de plata ...
Actuación
Ajustar los valores (especialmente los primitivos) a una instancia adicional puede degradar el rendimiento. En lazos cerrados, esto podría volverse notable o incluso peor.
Tenga en cuenta que el compilador podría evitar la referencia adicional para vidas cortas de
Optionals. En Java 10 , los tipos de valor pueden reducir o eliminar aún más la penalización.Publicación por entregas
Optionalno es serializable, pero una solución alternativa no es demasiado complicada.Invariancia
Debido a la invariabilidad de los tipos genéricos en Java, ciertas operaciones se vuelven engorrosas cuando el tipo de valor real se inserta en un argumento de tipo genérico. Aquí se da un ejemplo (ver "Polimorfismo paramétrico") .
fuente
Lists. Este es el caso cuando es importante que cierto elemento esté ubicado en un cierto índice, pero el elemento puede estar presente o no. Eso se comunica claramente por unList<Optional<T>>tipo. Si, por otro lado, solo es importante qué objetos que son miembros alguna colección, entonces no tiene sentido.Optionalser pasado a un método puede sernull. Entonces, ¿qué has ganado? Ahora tienes que hacer dos cheques. Ver stackoverflow.com/a/31923042/650176Optional(lo que debería ser el caso si estás dispuesto a pasarlo como argumento)nullnunca es un valor legal. Entonces, llamar a un método con un parámetro explícitonulles obviamente un error.Personalmente, prefiero usar la herramienta de inspección de código de IntelliJ para usar
@NotNully@Nullableverificar, ya que estos son en gran parte tiempo de compilación (puede tener algunas verificaciones de tiempo de ejecución) Esto tiene una sobrecarga menor en términos de legibilidad de código y rendimiento de tiempo de ejecución. No es tan riguroso como usar Opcional, sin embargo, esta falta de rigor debería estar respaldada por pruebas unitarias decentes.Esto funciona con Java 5 y no es necesario ajustar y desenvolver valores. (o crear objetos de envoltura)
fuente
@Nonnullpersonalmente - trabaja con FindBugs;)@Nonnull @NotNull etcCreo que Guava Opcional y su página wiki lo explican bastante bien:
Optionalagrega algo de sobrecarga, pero creo que su clara ventaja es hacer explícito que un objeto podría estar ausente y exige que los programadores manejen la situación. Impide que alguien olvide el querido!= nullcheque.Tomando el ejemplo de 2 , creo que es un código mucho más explícito para escribir:
que
Para mí,
Optionalmejor captura el hecho de que no hay una tarjeta de sonido presente.Mis 2 ¢ sobre tus puntos:
public Optional<Foo> findFoo(String id);- No estoy seguro de esto. Tal vez devolvería unResult<Foo>que podría estar vacío o contener unFoo. Es un concepto similar, pero en realidad noOptional.public Foo doSomething(String id, Optional<Bar> barOptional);- Preferiría @Nullable y una comprobación de findbugs, como en la respuesta de Peter Lawrey - vea también esta discusión .Optional<Index> getIndex()para indicar explícitamente que el libro podría no tener un índice.En general, trataría de minimizar el paso
nulls. (Una vez quemada ...) Creo que vale la pena encontrar las abstracciones apropiadas e indicar a los demás programadores qué representa un cierto valor de retorno.fuente
soundcard.ifPresent(System.out::println). LlamarisPresentes semánticamente lo mismo que verificarnull.if(soundcard != null && soundcard.isPresent()). Aunque hacer una API que devuelva un Opcional y también podría ser nulo es algo que espero que nadie haga.Del tutorial de Oracle :
fuente
Aquí hay un buen artículo que muestra la utilidad del caso de uso # 1. Hay este código
se transforma a esto
utilizando Opcional como valor de retorno de los métodos getter respectivos .
fuente
Aquí hay un uso interesante (creo) para ... Pruebas.
Tengo la intención de probar uno de mis proyectos y, por lo tanto, construir afirmaciones; solo hay cosas que tengo que verificar y otras que no.
Por lo tanto, construyo cosas para afirmar y uso una afirmación para verificarlas, así:
En la clase NodeAssert, hago esto:
¡Lo que significa que la afirmación realmente solo se activa si quiero verificar la etiqueta!
fuente
Optionalclase le permite evitar el usonully proporcionar una mejor alternativa:Esto alienta al desarrollador a hacer comprobaciones de presencia para evitar no ser capturado
NullPointerException.La API se documenta mejor porque es posible ver dónde esperar los valores que pueden estar ausentes.
Optionalproporciona API conveniente para trabajar más con el objetoisPresent():;get();orElse();orElseGet();orElseThrow();map();filter();flatmap().Además, muchos marcos utilizan activamente este tipo de datos y lo devuelven desde su API.
fuente
En Java, simplemente no los use a menos que sea adicto a la programación funcional.
No tienen lugar como argumentos de método (prometo que alguien algún día le pasará una opción nula, no solo una opción que esté vacía).
Tienen sentido para los valores de retorno, pero invitan a la clase del cliente a seguir estirando la cadena de desarrollo del comportamiento.
FP y las cadenas tienen poco lugar en un lenguaje imperativo como Java porque hace que sea muy difícil depurar, no solo leer. Cuando te acercas a la línea, no puedes conocer el estado ni la intención del programa; tiene que intervenir para resolverlo (en un código que a menudo no es suyo y muchos marcos de pila profundos a pesar de los filtros de pasos) y debe agregar muchos puntos de interrupción para asegurarse de que pueda detenerse en el código / lambda que agregó, en lugar de simplemente caminar por las líneas triviales if / else / call.
Si desea una programación funcional, elija algo más que Java y espere que tenga las herramientas para depurar eso.
fuente
No creo que Opcional sea un sustituto general de los métodos que potencialmente devuelven valores nulos.
La idea básica es: la ausencia de un valor no significa que esté potencialmente disponible en el futuro. Es una diferencia entre findById (-1) y findById (67).
La información principal de los opcionales para la persona que llama es que no puede contar con el valor dado, pero puede estar disponible en algún momento. Tal vez desaparecerá nuevamente y volverá más tarde una vez más. Es como un interruptor de encendido / apagado. Tiene la "opción" para encender o apagar la luz. Pero no tiene opción si no tiene una luz para encender.
Por lo tanto, me resulta demasiado desordenado introducir los opcionales en todas partes donde anteriormente se devolvió nulo. Todavía usaré nulo, pero solo en áreas restringidas como la raíz de un árbol, inicialización perezosa y métodos de búsqueda explícitos.
fuente
Parece
Optionalsólo es útil si el tipo T en opcional es un tipo simple comoint,long,char, etc Para las clases "reales", que no tiene sentido para mí, como se puede utilizar unnullvalor de todos modos.Creo que fue tomado de aquí (o de otro concepto de lenguaje similar).
Nullable<T>En C #, esto
Nullable<T>se introdujo hace mucho tiempo para ajustar los tipos de valor.fuente
Optionalde hechojava.util.Optional.An tiene una semántica similar a una instancia no modificable del patrón de diseño Iterator :
OptionalisPresent())get()) si se refiere a un objetonext()método).Por lo tanto, considere devolver o pasar un
Optionalcontexto en el que anteriormente podría haber considerado utilizar un JavaIterator.fuente
Java SE 8 presenta una nueva clase llamada java.util.Optional,
Puede crear un Opcional u Opcional vacío con valor nulo.
Y aquí hay un Opcional con un valor no nulo:
Hacer algo si hay un valor presente
Ahora que tiene un objeto Opcional, puede acceder a los métodos disponibles para tratar explícitamente la presencia o ausencia de valores. En lugar de tener que recordar hacer una verificación nula, de la siguiente manera:
Puede usar el método ifPresent () de la siguiente manera:
fuente