Java 8 Optional y NullPointerExceptions

El uso de Java 8 Optional es cada día más común para todos los que desarrollamos sobre Java 8. ¿Para qué sirve un tipo Optional? . Su uso esta centrado en eliminar muchos de los problemas que ocurren con el manejo de excepciones de tipo NullPointerException . Vamos a ver un ejemplo sencillo. Supongamos que partimos de una clase de servicio que tiene una lista de Personas que deseamos filtrar. Vamos a ver una primera versión el código:


package com.arquitecturajava;

import java.util.ArrayList;
import java.util.List;

public class ServicioPersonas {
	
	static List<Persona> lista= new ArrayList<Persona>();
	static {
		
		lista.add(new Persona("pedro"));
		lista.add(new Persona("angel"));
		lista.add(new Persona("ana"));
	}
	
	
	public Persona buscar(String nombre) {
		
		 for (Persona p:lista) {
			 
			 if (p.getNombre().equals(nombre)) {
				 return p;
			 }
		 }
		 
		 return null;
	}
	
}

En este caso usamos un bucle forEach para buscar la Persona que coincide con el nombre y devolverla. Un programa main puede hacer uso de nuestra clase de Servicio.


package com.arquitecturajava;

public class Principal2 {

	public static void main(String[] args) {
		
		
		ServicioPersonas sp= new ServicioPersonas();
		Persona p=sp.buscar("gema");
		System.out.println(p.getNombre());
		
	}
}

El programa funciona correctamente e imprime angel por la consola:

Java 8 Optional

Sin embargo no sucedería lo mismo si pasáramos como parámetro “gema” ya que esta Persona no existe en la lista y el resultado será un NullPointerException:

Java 8 Optional Exception

Una gran parte de nuestros problemas en tiempo de ejecución vienen dados por este tipo de excepciones.

Un ejemplo de Java 8 Optional

Vamos a abordar el mismo ejemplo pero usando un Java Optional. Para ello modificamos el método buscar de la clase de servicio creando una variable de tipo Optional:


public Optional<Persona> buscar(String nombre) {
		
		 for (Persona p:lista) {
			 
			 if (p.getNombre()==nombre) {
				 return  Optional.of(p);
			 }
		 }
		 
		 return Optional.empty();
	}

Esto nos obligará a modificar el código de nuestro programa main y usar los optionals evitando las excepciones de tipo NullPointer :


ServicioPersonasOptional sp= new ServicioPersonasOptional();
Optional<Persona> op=sp.buscar("gema");
if (op.isPresent()) {
System.out.println(op.get().getNombre());
}else {	
System.out.println("no hay registros");
}

Los tipos optional soportan métodos como isPresent() que fuerzan un checkeo antes de acceder al valor.Las propias APIS de Java hacen un uso fuerte de este concepto . Por ejemplo en vez de usar un bucle for para buscar en la lista podríamos haber usado un Stream, el cual devuelve un optional


public Optional<Persona> buscar(String nombre) {
 
 return lista.stream().filter(p->p.getNombre()==nombre).findFirst();
 }
 

El uso de Java 8 Optional es muy práctico y refuerza los conceptos de programación funcional que tenemos en el lenguaje.

Otros artículos relacionados: Java Lambda,  Programación Funcional, Java 8 Streams Java Functional Interface

It's only fair to share...Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

About Cecilio Álvarez Caules

Cecilio Álvarez Caules Sun Certified Enterprise Architech (J2EE/JEE).

11 Responses to Java 8 Optional y NullPointerExceptions

  1. Carlos 10 Febrero, 2017 at 19:23 #

    Muy bueno, no conocía este objeto Optional. Pero creo que podriamos conseguir los mismos resultados en el primer ejemplo, validando que el retono no sea nulo. Es decir, como buena práctica de programación siempre deberíamos validar que un objeto no sea nulo antes de hacer uso de ellos. Tanto los metodos get, set, parser, etc. Saludos!

  2. Andrés Alarcón 10 Febrero, 2017 at 18:05 #

    Cecilio llevo hace rato siguiendo tu blog y me gusta como le agregas simplicidad a tus explicaciones, muchas gracias.

    • Cecilio Álvarez Caules 10 Febrero, 2017 at 20:55 #

      me alegro que sea útil 🙂

  3. Agustín Ventura 10 Febrero, 2017 at 11:22 #

    Buenas Cecilio,

    Como siempre muy buen artículo introductorio, sin embargo creo que esta vez habría que profundizar algo más.
    Desde mi punto de vista el isPresent es un vulgar remedo del != null, la auténtica funcionalidad del Optional viene cuando la encadenas con los Streams, por ejemplo, podríamos reescribir tu último ejemplo así:

    public String buscar(String nombre) {
    return lista.stream().filter(p->p.getNombre()==nombre).findFirst().orElse(“no hay registros”);
    }

    Y de esta manera te puedes ahorrar las comparaciones arriba 🙂

    ¿Qué te parece?

    • Cecilio Álvarez Caules 10 Febrero, 2017 at 15:03 #

      Me parece …. diferente , que no mejor, ni tampoco peor 🙂 . Es cierto que es mas compacto en eso no hay ninguna duda . Lo que pasa es que entonces hay que asumir que el usuario del API tiene claro lo que devuelve el método con “no hay registros”. Algo de lo cual el método no informa en ningún momento y habría que ir al JavaDoc. En cambio con el retorno del Optional si estamos informando de algo con claridad. ¿ No se si te he aportado algo? ya me dices tu punto de vista.

      • Agustin Ventura 10 Febrero, 2017 at 21:13 #

        Desde luego siempre es más limpio devolver un Optional que un null, aunque el gran problema de Optional es que hoy por hoy no es Serializable, lo cual limita un poco su utilidad a APIs de librerías.
        Por otra parte, el ejemplo era por “refactorizar” un poco tu código y mostrar algo más de uso de Optional junto con la API de Streams. Como bien señalas es mala práctica devolver ese “no hay registros” (y en general devolver códigos ocultos que te obliguen a consultar la documentación =)), así que por elaborar un poco más el ejemplo, podríamos hacer lo siguiente:
        public String buscar(String nombre) {
        return lista.stream().filter(p->p.getNombre()==nombre).findFirst().orElseThrow(IllegalArgumentException::new);
        }

        O nuestra propia excepción, claro esta.
        En cualquier caso entiendo que esto escapa un poco al alcance de este estupendo artículo 🙂

        Un placer charlar contigo 🙂

        • Cecilio Álvarez Caules 13 Febrero, 2017 at 22:00 #

          gracias 🙂

  4. Alex 9 Febrero, 2017 at 16:22 #

    Como comentario… este tipo de comparaciones no se deberían de hacer: p.getNombre()==nombre en su caso usar String.equals(String)

    • Cecilio Álvarez Caules 9 Febrero, 2017 at 22:14 #

      Tienes toda la razón del mundo , gracias por la corrección llevo unas semanas en el mundo JavaScript y todo se pega 🙂

Deja un comentario