Tome los dos ejemplos de código:
if(optional.isPresent()) {
//do your thing
}
if(variable != null) {
//do your thing
}
Por lo que puedo decir, la diferencia más obvia es que el Opcional requiere la creación de un objeto adicional.
Sin embargo, muchas personas han comenzado a adoptar rápidamente los opcionales. ¿Cuál es la ventaja de usar opcionales versus un cheque nulo?
if
declaraciones son taaaaaai en la última década, y todos están usando abstracciones de mónada y lambdas ahora.if(x.isPresent) fails_on_null(x.get)
salir del sistema de tipos y mantener la garantía de que el código no se romperá "en su cabeza" sobre la distancia (ciertamente corta) entre la condición y la llamada a la función. Enoptional.ifPresent(fails_on_null)
el sistema de tipos le garantizamos esto, y no tiene que preocuparse.Optional.ifPresent
(y varias otras construcciones de Java) es que solo puede modificar efectivamente las variables finales y no puede lanzar excepciones comprobadas. Esa es una razón suficiente para evitar a menudoifPresent
, desafortunadamente.Respuestas:
Optional
aprovecha el sistema de tipos para hacer el trabajo que de lo contrario tendría que hacer todo en su cabeza: recordar si una referencia dada puede ser o nonull
. Esto es bueno. Siempre es inteligente dejar que el compilador maneje trabajos aburridos y reservar el pensamiento humano para un trabajo creativo e interesante.Sin
Optional
, cada referencia en su código es como una bomba sin explotar. Acceder a él puede hacer algo útil, o puede terminar su programa con una excepción.Con Opcional y sin
null
, cada acceso a una referencia normal tiene éxito, y cada referencia a una Opcional tiene éxito a menos que esté desarmado y no haya podido comprobarlo. Esa es una gran victoria en mantenibilidad.Desafortunadamente, la mayoría de los idiomas que ahora ofrecen
Optional
no se han eliminadonull
, por lo que solo puede beneficiarse del concepto instituyendo una política estricta de "absolutamente nonull
, nunca". Por lo tanto,Optional
por ejemplo, Java no es tan convincente como debería ser idealmente.fuente
Optional
solo para recordarle que el valor podría ser nuloUn
Optional
trae un tipeo más fuerte a las operaciones que pueden fallar, como lo han cubierto las otras respuestas, pero eso está lejos de ser lo más interesante o valioso queOptionals
trae a la mesa. Mucho más útil es la capacidad de retrasar o evitar la verificación de fallas, y componer fácilmente muchas operaciones que pueden fallar.Considere si tenía su
optional
variable de su código de ejemplo, entonces tuvo que realizar dos pasos adicionales que cada uno podría fallar. Si falla algún paso en el camino, en su lugar, desea devolver un valor predeterminado. UsandoOptionals
correctamente, terminas con algo como esto:Con
null
Hubiera tenido que verificar tres vecesnull
antes de continuar, lo que agrega mucha complejidad y dolores de cabeza de mantenimiento al código.Optionals
tener ese control integrado en las funcionesflatMap
yorElse
.Tenga en cuenta que no llamé
isPresent
una vez, lo que debe pensar como un olor a código cuando lo usoOptionals
. Eso no significa necesariamente que nunca debas usarloisPresent
, solo que debes analizar detenidamente cualquier código que lo haga, para ver si hay una mejor manera. De lo contrario, tiene razón, solo está obteniendo un beneficio de seguridad de tipo marginal sobre el usonull
.También tenga en cuenta que no estoy tan preocupado por encapsular todo esto en una sola función, para proteger otras partes de mi código de punteros nulos de resultados intermedios. Si tiene más sentido tener mi
.orElse(defaultValue)
en otra función, por ejemplo, tengo muchos menos reparos en ponerla allí, y es mucho más fácil componer las operaciones entre diferentes funciones según sea necesario.fuente
Destaca la posibilidad de nulo como una respuesta válida, que la gente a menudo asume (correcta o incorrectamente) no se devolverá. Destacar las pocas veces que nulo es válido permite omitir ensuciar su código con un gran número de comprobaciones nulas sin sentido.
Idealmente, establecer una variable en nulo sería un error de tiempo de compilación en cualquier lugar menos en un opcional; eliminando excepciones de puntero nulo en tiempo de ejecución. Obviamente, la compatibilidad con versiones anteriores impide esto, lamentablemente
fuente
Dejame darte un ejemplo:
Está bastante claro para qué está destinado este método. Pero, ¿qué sucede si el repositorio no contiene un usuario con una identificación dada? ¿Podría arrojar una excepción o tal vez devuelva nulo?
Segundo ejemplo
Ahora, ¿qué sucede aquí si no hay un usuario con una identificación dada? Correcto, obtienes la instancia Optional.absent () y puedes verificarlo con Optional.isPresent (). La firma del método con Opcional es más explícita sobre su contrato. Es inmediatamente claro cómo se supone que debe comportarse el método.
También tiene un beneficio al leer el código del cliente:
He entrenado mi ojo para ver .get () como un código de olor inmediato. Significa que el cliente ignora a propósito el contrato del método invocado. Es mucho más fácil ver esto que sin Opcional, porque en ese caso no se sabe inmediatamente cuál es el contrato del método llamado (si permite nulo o no en su devolución), por lo que debe verificarlo primero.
Opcional se usa con la convención de que los métodos con el tipo de retorno Opcional nunca devuelven nulo y generalmente también con la convención (menos fuerte) ese método sin el tipo de retorno Opcional nunca devuelve nulo (pero es mejor anotarlo con @Nonnull, @NotNull o similar) .
fuente
Un le
Optional<T>
permite tener "falla" o "ningún resultado" como un valor de respuesta / retorno válido para sus métodos (piense, por ejemplo, en una búsqueda en la base de datos). Usar un enOptional
lugar de usarnull
para indicar la falla / ningún resultado tiene algunas ventajas:null
podría ser devuelto.null
, al menos en mi opinión, no debe usarse para indicar nada, ya que la semántica podría no ser totalmente clara. Debe usarse para decirle al recolector de basura que el objeto al que se hace referencia anteriormente puede ser recolectado.Optional
clase proporciona muchos métodos agradables para trabajar condicionalmente con los valores (por ejemplo,ifPresent()
) o definir valores predeterminados de forma transparente (orElse()
).Desafortunadamente, no elimina por completo la necesidad de
null
verificaciones en el código, ya que elOptional
objeto en sí podría serlonull
.fuente
Además de las otras respuestas, la otra gran ventaja de los opcionales cuando se trata de escribir código limpio es que puede usar una expresión Lambda en el caso de que el valor esté presente, como se muestra a continuación:
fuente
Considere el siguiente método:
Ahora veamos un código de llamada:
Esto provoca un bloqueo potencialmente difícil de rastrear en otro lugar, porque
dance
no esperaba un valor nulo.Esto provoca un error de compilación, porque dance esperaba un
Person
noOptional<Person>
Si no tuviera una persona, esto ocasiona una excepción en esta línea, en el punto donde intenté convertirla
Optional<Person>
en una Persona de manera ilegítima . La clave es que, a diferencia de pasar un valor nulo, la excepción se traza hasta aquí, no en alguna otra ubicación del programa.Para poner todo junto: el uso indebido opcional produce problemas más fáciles de rastrear, el mal uso de nulo causa problemas difíciles de rastrear.
fuente
Optional.get()
su código está mal escrito, casi nunca debería llamar a Opcional.get sin verificarOptional.isPresent()
primero (como se indica en el OP) o podría escribiroptionalPersion.ifPresent(myObj::dance)
.En Objective-C, todas las referencias a objetos son opcionales. Debido a esto, el código que publicaste es una tontería.
Código como el anterior es inaudito en Objective-C. En cambio, el programador simplemente:
Si
variable
contiene un valor, sedoThing
le llamará. Si no, no hay daño. El programa lo tratará como un no-op y continuará ejecutándose.Este es el beneficio real de los opcionales. No tiene que ensuciar su código
if (obj != nil)
.fuente
El problema obvio aquí es que si "opcional" realmente está faltante (es decir, es nulo), entonces el código se va a volar con un NullReferenceException (o similar) tratando de llamar a cualquier método en una referencia de objeto nulo!
Es posible que desee escribir un método estático de clase Helper que determine la nulidad de cualquier tipo de objeto dado, algo como esto:
o, quizás, más útilmente:
Pero, ¿alguno de estos es realmente más legible / comprensible / mantenible que el original?
fuente