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:
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:
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:
Muy bueno y útil, tanto el artículo como los comentarios 😊
gracias 🙂
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!
Al final el:
if (op.isPresent()) {
System.out.println(op.get().getNombre());
}else {
System.out.println(“no hay registros”);
}
no es menos código que:
if (p!=null){
…
} else{
….
}
Recuerda que un método que puede devolver null , no se sabe si lo devuelve en cambio con un optional esta todo más claro y te puedes proteger de una forma más elegante ya que tienes la certeza
También podríamos haber puesto en la línea 26
return new Persona ()
Y comprobar luego su está vacío.
No acabo de verle la utilidad práctica Cecilio.
A no ser que lo que queramos es evitar las dichosas nullpointerexcrption
Eso es lo que se quiere evitar 🙂
Cecilio llevo hace rato siguiendo tu blog y me gusta como le agregas simplicidad a tus explicaciones, muchas gracias.
me alegro que sea útil 🙂
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?
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.
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… Read more »
gracias 🙂
Como comentario… este tipo de comparaciones no se deberían de hacer: p.getNombre()==nombre en su caso usar String.equals(String)
Tienes toda la razón del mundo , gracias por la corrección llevo unas semanas en el mundo JavaScript y todo se pega 🙂
A todos nos ha pasado alguna vez! xD
pues sí 🙂