El concepto de Java Optional Repository llega en Java 8 y hace referencia a cómo podemos usar los tipos Optional dentro de nuestras clases clásicas de repositorio. El ejemplo mas clásico es el método BuscarUno o findOne() a nivel de Java Persistence API . Este método nos permite buscar un elemento concreto por clave primaria utilizando el repositorio.
En muchas ocasiones el programa puede dar problemas en el caso de que no se encuentre ningún elemento ya que cuando intentamos acceder a sus campos saltará una excepción de tipo NullPointer.
&lt;br&gt;<br> package repositorios.ejemplo1;&lt;/p&gt;<br> &lt;p&gt;import javax.persistence.EntityManager;&lt;/p&gt;<br> &lt;p&gt;import model.Cliente;&lt;/p&gt;<br> &lt;p&gt;public class ClienteRepository {&lt;/p&gt;<br> &lt;p&gt; private EntityManager entityManager;&lt;/p&gt;<br> &lt;p&gt; public EntityManager getEntityManager() {&lt;br&gt;<br> return entityManager;&lt;br&gt;<br> }&lt;/p&gt;<br> &lt;p&gt; public void setEntityManager(EntityManager entityManager) {&lt;br&gt;<br> this.entityManager = entityManager;&lt;br&gt;<br> }&lt;/p&gt;<br> &lt;p&gt; public Cliente buscarUno(String dni) {&lt;/p&gt;<br> &lt;p&gt; return entityManager.find(Cliente.class, "1");&lt;br&gt;<br> }&lt;br&gt;<br> }&lt;/p&gt;<br> &lt;p&gt;
&lt;br&gt;<br> package repositorios;&lt;/p&gt;<br> &lt;p&gt;import javax.persistence.EntityManager;&lt;br&gt;<br> import javax.persistence.EntityManagerFactory;&lt;br&gt;<br> import javax.persistence.Persistence;&lt;/p&gt;<br> &lt;p&gt;import model.Cliente;&lt;br&gt;<br> import repositorios.ejemplo1.ClienteRepository;&lt;/p&gt;<br> &lt;p&gt;public class Principal {&lt;/p&gt;<br> &lt;p&gt; public static void main(String[] args) {&lt;/p&gt;<br> &lt;p&gt; EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa001");&lt;br&gt;<br> EntityManager em = emf.createEntityManager();&lt;/p&gt;<br> &lt;p&gt; ClienteRepository repositorio = new ClienteRepository();&lt;/p&gt;<br> &lt;p&gt; Cliente cliente=repositorio.buscarUno("1");&lt;br&gt;<br> System.out.println(cliente.getNombre());&lt;/p&gt;<br> &lt;p&gt; }&lt;/p&gt;<br> &lt;p&gt;}&lt;/p&gt;<br> &lt;p&gt;
Java Optional Repository
Para evitar estos problemas podemos apoyarnos en Java 8 y hacer uso de los tipos Optional que nos obligan a comprobar si un tipo esta a null antes de acceder a la información que almacena.
Veámoslos en código:
&lt;/p&gt;<br> &lt;p&gt;package repositorios.ejemplo2;&lt;/p&gt;<br> &lt;p&gt;import java.util.Optional;&lt;/p&gt;<br> &lt;p&gt;import javax.persistence.EntityManager;&lt;br&gt;<br> import javax.persistence.EntityManagerFactory;&lt;br&gt;<br> import javax.persistence.Persistence;&lt;/p&gt;<br> &lt;p&gt;import model.Cliente;&lt;/p&gt;<br> &lt;p&gt;public class ClienteRepository {&lt;/p&gt;<br> &lt;p&gt; private EntityManager entityManager;&lt;/p&gt;<br> &lt;p&gt; public EntityManager getEntityManager() {&lt;br&gt;<br> return entityManager;&lt;br&gt;<br> }&lt;/p&gt;<br> &lt;p&gt; public void setEntityManager(EntityManager entityManager) {&lt;br&gt;<br> this.entityManager = entityManager;&lt;br&gt;<br> }&lt;/p&gt;<br> &lt;p&gt; public ClienteRepository(EntityManager entityManager) {&lt;br&gt;<br> super();&lt;br&gt;<br> this.entityManager = entityManager;&lt;br&gt;<br> }&lt;/p&gt;<br> &lt;p&gt; public Optional&amp;lt;Cliente&amp;gt; buscarUno(String dni) {&lt;/p&gt;<br> &lt;p&gt; Cliente cliente = entityManager.find(Cliente.class, dni);&lt;/p&gt;<br> &lt;p&gt; if (cliente == null) {&lt;/p&gt;<br> &lt;p&gt; return Optional.empty();&lt;/p&gt;<br> &lt;p&gt; } else {&lt;/p&gt;<br> &lt;p&gt; return Optional.of(cliente);&lt;br&gt;<br> }&lt;/p&gt;<br> &lt;p&gt; }&lt;br&gt;<br> }&lt;/p&gt;<br> &lt;p&gt;
Ahora la clase de repositorio hace uso de JPA pero apoyandose en tipos Optional de Java 8 de tal forma que cuando queramos acceder desde un cliente nos obligará a comprobar si existe un valor antes de imprimirlo por la pantalla.
&lt;/p&gt;<br> &lt;p&gt;package repositorios;&lt;/p&gt;<br> &lt;p&gt;import java.util.Optional;&lt;/p&gt;<br> &lt;p&gt;import javax.persistence.EntityManager;&lt;br&gt;<br> import javax.persistence.EntityManagerFactory;&lt;br&gt;<br> import javax.persistence.Persistence;&lt;/p&gt;<br> &lt;p&gt;import model.Cliente;&lt;br&gt;<br> import repositorios.ejemplo2.ClienteRepository;&lt;/p&gt;<br> &lt;p&gt;public class Principal2 {&lt;/p&gt;<br> &lt;p&gt; public static void main(String[] args) {&lt;/p&gt;<br> &lt;p&gt; EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa001");&lt;br&gt;<br> EntityManager em = emf.createEntityManager();&lt;/p&gt;<br> &lt;p&gt; ClienteRepository repositorio = new ClienteRepository(em);&lt;/p&gt;<br> &lt;p&gt; Optional&amp;lt;Cliente&amp;gt; cliente=repositorio.buscarUno("1");&lt;/p&gt;<br> &lt;p&gt; if (cliente.isPresent()) {&lt;br&gt;<br> System.out.println(cliente.get().getNombre());&lt;br&gt;<br> }&lt;/p&gt;<br> &lt;p&gt; }&lt;/p&gt;<br> &lt;p&gt;}&lt;/p&gt;<br> &lt;p&gt;
Aprendamos a usar Java Optional Repository como un refactor importante a la hora de construir nuestras clases clásicas de repositorio.
- Java Optional Stream y reference methods
- Java Optional ifPresent y como utilizarlo
- Java 8 Optional y NullPointerExceptions
- Java 8
Buenos días. Realmente el uso de “if (cliente.isPresent())” o “if (null != cliente)” son iguales y en Java 8 o Superior deberían evitarse. Muchos tienen una idea erronea de la forma de utilizar la clase Optional y al esta contar con los métodos isPresent() y get() (los cuales hacen que nuestro código siga siendo muy similar a lo que ya conocemos) los usan erroneamente. La forma correcta de usar Optional es por medio de los métodos que reciben interfaces funcionales. Así pues si queremos hacer algo cuando el objeto exista sería algo así: cliente.ifPresent(c->System.out.println(c.getNombre())) o incluso mejor, podemos hacer una… Read more »
Gracias por el aporte , siempre hay mil combinaciones posibles , lo importante del uso de Optional es que obliga a comprobar la variable 🙂 . El como luego lo redibujes … no me parece tan crítico. Pero es cierto que tu aporte simplifica 🙂 . Gracias
Buenos días Cecilio,
Muchas gracias por la información que publicas.
En este caso al usar el Optional estamos añadiendo un “if (cliente.isPresent())” a la hora de imprimir el nombre. ¿Qué ventaja tiene esto con respecto a “if (null != cliente)”?
Saludos.
Se gana bastante en legibilidad, es una expresión bastante más cercana al lenguaje natural.
Es interesante esto que comentas.
Para mejorar la legibilidad introduzco el código if (null != cliente) en un método correctamente nombrado y que devuelva un boolean.
Le estoy dando vueltas y la única ventaja que veo es que si esperas un Optional ya sabes que puede venir o no, en cambio en cualquier otro método puedes suponer que nunca vendrá un null y equivocarte.
Saludos.
gracias 🙂
No tendría nada más que la ventaja de verte obligado a comprobar 🙂 . En otro comentario describen como compactarlo más