Muchas veces cuando estamos probando nuestra aplicación nos encontramos con un bug y cuando observamos la consola, vemos unas poderosas palabras: “NullPointerException”. En este artículo vamos a ver cómo podemos manejar estas excepciones con una clase de java conocida como “Optional”.
¿Que es un Optional? ¿Para qué sirve?
Empecemos por el principio. Un Optional es una clase que puede o no contener un valor, es decir, que se comporta como un wrapper para cualquier tipo de objeto que pueda o no ser nulo.
Ahora que ya sabemos que es, veamos cómo nos beneficiamos con esta clase. Su principal ventaja es que nos permite manejar los NullPointer, o sea que no tendremos que ir preguntando si un objeto es nulo antes de hacer algo. Otra ventaja importante es que ayudan a la legibilidad del código, por lo que será más fácil leerlo y a su vez mantenerlo.
Veamos algunos ejemplos de cuando no usamos Optionals y de cuando si los usamos.
Sin Optionals
Precio precio;
Videojuego pokemonEspada = obtenerVideojuego("Pokemon Espada");
if(pokemonEspada != null) {
precio = pokemonEspada.precio;
if(precio != null) {
imprimirCentavos(precio.centavos);
}
}
Con Optionals
Optional<Videojuego> pokemonEspada = obtenerVideojuego("Pokemon Espada");
pokemonEspada.ifPresent(juego ->
juego.precio.ifPresent(precio ->
imprimirCentavos(precio.centavos);
);
);
Métodos de la clase
Vamos a ver algunos métodos bastante útiles a la hora de trabajar con Optionals. Empecemos con los métodos de creación estos son:
- Optional.empty(): esto nos devuelve un Optional vacío, es decir que no hay ningún valor presente dentro de este.
- Optional.of(<Objeto>): esto creará un Optional del objeto que le pasemos, pero cuidado si le pasamos un “null” lanzara un NullPointerException.
- Optional.ofNullable(<Objeto>): este también creará un Optional, pero con la diferencia de que no le afecte si el objeto que le pasamos es nulo. En caso de pasarle un nulo este creara un Optional.empty.
Ya vimos cómo crearlos, ahora sigamos con los métodos que nos permiten verificar la existencia (o no) del valor. Estos son:
- <Opcional>.isPresent(): este nos dirá si existe un valor dentro del Optional o no.
- <Opcional>.isEmpty(): es parecido al anterior, solo que este nos dice si el contenido del Optional es nulo.
- <Opcional>.ifPresent(<Consumer>): este nos permitirá ejecutar un consumer en caso de que exista un valor en el Optional.
Ahora que sabemos cómo ver su existencia, veamos cómo obtener el valor dentro de un Optional. Estos son:
- <Opcional>.get(): este nos devolverá el valor dentro del Optional, aunque si este está vacío lanzará una “NoSuchElementException”.
- <Opcional>.orElse(<ObjetoDelMismoTipoQueContieneElOptional>): para evitar el problema del método anterior existe el “orElse”. Este nos permitirá, en caso de no existir un valor dentro del Optional, devolver el valor que le pasemos como parámetro.
- <Opcional>.orElseGet(<Supplier>): es parecido al anterior. En caso de no existir el valor, este nos permitirá ejecutar un Supplier, es decir, devolver un valor en caso de que el Optional este vacío.
Buenas prácticas
Ahora que ya sabemos que son los Optionals y cómo usarlos, veamos dónde es conveniente usarlos sin salirnos de lo que intentan resolver.
No olvidemos que tratan de reducir los NullPointerExceptions en Java a la vez que aumentan la legibilidad del código. Teniendo esto en cuenta ¿Cuando los usamos? Una buena práctica es usarlos siempre como un tipo de retorno de un método, ya que este nos permitirá manejarlo bien en caso de que no exista un valor dentro del Optional.
Conclusión
Entonces, después de todo lo que vimos, cerremos con una pequeña conclusión: Los Optionals nos permiten manejar valores que podrían no existir. Esto nos ayuda a reducir la cantidad de excepciones generadas por valores nulos. La clase Optional cuenta con varios métodos útiles que nos van a permitir manejar tanto la creación, la obtención y la verificación de los valores. Pero no te olvides de que esta clase está pensada para ser un tipo de retorno, así que evita usarla en otros lados.