Está en la página 1de 42

T H E B I L L I O N D O L L A R M I S TA K E

Quien
soy
aloaisa
• Más decepcionante que los Generics de Java
• Peor que la barra invertida de Windows \

• Más problemático que la comparación en JS ===

• Más común que PHP

• Más lamentable que UTF-16

• Más escandaloso que MongoDB

• Más confuso que el Pre-Compilador de C

•El peor error se produjo en 1965!!


No eres un verdadero
programador
hasta que no has tenido un
NullPointerException
Tony Hoare

“I call it my billion-dollar mistake”

“ It was the invention of the null reference in 1965. At that time, I was designing the
first comprehensive type system for references in an object oriented language (ALGOL
W). My goal was to ensure that all use of references should be absolutely safe, with
checking performed automatically by the compiler. But I couldn't resist the temptation
to put in a null reference, simply because it was so easy to implement. This has led to
innumerable errors, vulnerabilities, and system crashes, which have probably caused a
billion dollars of pain and damage in the last forty years. ”
Que pasa con los nulls?
Que pasa con los nulls?

• NullPointerException es de lejos la excepción más común en Java

• Empeora la legibilidad llenando todo con chequeos de nulls

• Rompe la filosofía Java de ocultar a los desarrolladores los punteros.

• Es un agujero en el Sistema de Tipos

• No tiene un sentido semántico en particular.

• Es un mal modelo para representar la ausencia de valor para un lenguaje


estáticamente tipado.
“La ausencia de señal, nunca
debe ser usada como señal”
J. Bigalow 1947
null != Ausencia de valor
Problema típico en POO
Problema típico en POO

• Muchos ordenadores no tienen Soundcard.


¿Que devolvemos entonces?

• Comúnmente y como mala práctica, se suele usar


null para indicar la ausencia de SoundCard

• Con lo que el resultado será un NullPointerException en tiempo de


ejecución y el programa se parará.
¿Como se ha resuelto en otros lenguajes ??

• Lenguajes como C# o Groovy tienen el “Safe navigation operator” ?.

• A la variable version se le asignará null si computer es null,


getSoundCard() devuelve null o getUSB() devuelve null.

• No es necesario escribir código complejo para chequear los null


Groovy - Elvis Operator ?:

• Es usado en casos simples cuando la variable necesita un valor por


defecto

• En el caso que .getVersion() nos devolviera null podríamos devolver


un valor por defecto de esta forma:
Otros puntos de vista
• Haskell: Incluye el tipo Maybe
• Maybe puede contener un valor de un tipo dado o nada, ya que
no existe el concepto de nulo

• En esencia encapsula a un Optional

• Scala: Similar con Option[T]


• Encapsula la presencia o la ausencia de un valor de un tipo T

• Tenemos que chequear si el valor está presente, lo cual es similar a


el chequeo de nulos.
• Fuerza al programador a controlarlo a través del sistema de
tipos
Y en Java ??
• Solución 1: (Guarrada)

• Desagradable a la vista

• Debemos chequear todos


los valores para evitar
que nos pase

• Todos estos checks están en medio de la lógica

• Disminuye la legibilidad del programa


Y en Java ??
• Solución 2:
Podemos utilizar notaciones para restringir los contratos:

@NotNull y @Nullable (Java 8 > No estandars)

• @Nullable nos recuerda la necesidad de introducir un chequeo de null cuando


llamamos a métodos que pueden devolver nulos.

• @NotNull nos establece un contrato por el que el método no puede devolver


null - Y sus parámetros no pueden ser pasados como null
Y en Java ??
• Solución 3:
Patrón NullObject

• Añade complejidad

• Hay que crear bastantes NullObjects dependiendo de la arquitectura


Y en Java ??
• Solución 4: (Otra guarrada)
Devolver Null

• Mala práctica

• Fuente de NullPointerExceptions

• No estamos pensando en el caso de que sea vacío


Que pasa en Java 8 ??
• java.util.Optional<T>
• - Inspirado en la idea antes vista de
Haskell y Scala
• - Es una clase que encapsula un valor
opcional
Optional
• Un Optional puede ser visto como un contenedor de un solo
valor que puede contener un valor o no.
Optional

• Computer puede tener o no soundCard


• SoundCard puede tener o no puerto USB
Optional

• Este nuevo modelo refleja si un valor dado puede estar ausente

• Establece la intención del API

• Optional no es para reemplazar cada referencia nula

• Es para ayudarnos a hacer un diseño más comprensible

• Con la firma del método podemos saber si es un valor opcional

• Te obliga a hacer frente a la posible ausencia de valor


Y ahora qué ??
Creando Optionals

• Si soundCard fuera null se lanzaría un NullPointerException

• Si soundcard fuera null el resultado del Optional sería empty


.ifPresent()
• Ejecuta algo si el Opcional contiene algún valor

Antes:

Ahora:
.isPresent()

• Devuelve true o false dependiendo si contiene o no valor

• Podemos usarlos de esta forma para evitar excepciones

• Este no es el mejor uso, ya que no es mucho mejor al chequeo de


nulos
.get()

• Nos devuelve el valor contenido en el Optional

• Si no hay valor almacenado, dará un NoSuchElementException

• Podemos usarlos de esta forma para evitar excepciones


• Este no es el mejor uso, ya que no es mucho mejor al chequeo de
nulos
.orElse()
Patrón típico:

• Usando un objeto Optional podemos escribir este código usando


orElse()

• Este método provee un valor por defecto si el Optional está vacío.


.orElseGet()

• orElse() ejecuta siempre el contenido y lo devuelve si es el caso, a


no ser que sea un lambda

• orElseGet() solo ejecuta el código si le toca actuar


• Puede dar un NullPointerException si lo que ejecuta devuelve
null
.orElseThrow()

- Lanza la excepción que le digamos si el Optional está


vacío.
.filter()
Antes:

Ahora:

• El método filter() coge el valor como argumento

• Si el valor está presente en el Optional y la comprobación es true, el método filter()


devuelve el propio Optional

• Si el valor es vacío, devuelve un objeto Optional vacío


.map()
Antes:

Ahora:

• El valor dentro del Optional es pasado como argumento al método getUSB()

• Mientras que no pasa nada si está vacío


.flatMap()
Antes:

Ahora:

• getUSB() devuelve un objeto de tipo Optional<USB>


• Esto significa que el resultado de la primera operación map es un
objeto de tipo Optional<Optional<USB>>

• Como resultado, la llamada a getVersion() es inválida


.flatMap()
• El propósito es aplicar el método de transformación sobre el valor del Optional y
"aplanar" el resultado de dos niveles de Optional en uno solo.
.flatMap()
Antes:

Ahora:

• flatMap se utiliza para métodos que devuelven Optionals

• flatMap devuelve un Optional<USB> en lugar de un Optional<Optional<USB>>


• Podemos llamar a map() ya que getVersion() devuelve un String en vez de un objeto
Optional
Conclusiones:

• El propósito de Optional NO es reemplazar cada referencia nula en el código

• El propósito de Opcional es el poder diseñar mejores APIs

• Nos fuerza a extraer su valor y gestionarlo en el caso de su ausencia

• Nos protege de nullPointerExceptions

• Simplifica el código

• Un nullPointerException en producción puede hacerte perder mucha pasta!!


Recursos
http://www.oracle.com/technetwork/articles/
java/java8-optional-2175753.html

http://es.slideshare.net/Stephan.Schmidt/better-
strategies-for-null-handling-in-java

http://es.slideshare.net/Yokomark/17-50372457

http://www.slideshare.net/mariofusco/monadic-
java

https://www.jetbrains.com/help/idea/15.0/
nullable-and-notnull-annotations.html

https://www.lucidchart.com/techblog/2015/08/31/
the-worst-mistake-of-computer-science/

También podría gustarte