Clase Optional

La Clase Optional aparece a partir de Java 9, y simplemente hace referencia a un objeto o un valor null. Es decir hay situaciones en que ciertas sentencias nos podrá devolver algo o no. Siempre los “null” nos puede generar problemas, si usamos esta clase no. Ya que contempla la referencia a nada, intenta substituir a comprobaciones de tipo: “if (nota!=null) {}”

Resumen de cuatro métodos principales:

  • boolean isPresent(): devuelve si tiene valor o no.
  • get(): devuelve el objeto.
  • Optional.of(objeto): constructor de Optional estático (no acepta null).
  • Optional.ofNullable(objeto): mejor opción que la anterior ya que si acepta nulls.
  • boolean Optional.empty(): devuelve false si no existe el objeto.

Ejemplo:

public class Nota {

  private String asignatura;
  private double valor;
  public String getAsignatura() {
    return asignatura;
  }
  public void setAsignatura(String asignatura) {
    this.asignatura = asignatura;
  }
  public double getValor() {
    return valor;
  }
  public void setValor(double valor) {
    this.valor = valor;
  }
  public Nota(String asignatura, double valor) {
    super();
    this.asignatura = asignatura;
    this.valor = valor;
  }
}

public class Principal {

  public static void main(String[] args) {

    List<Nota> notas= new ArrayList<Nota>();
    notas.add(new Nota("matematicas",3));
    notas.add(new Nota("lengua",10));
    notas.add(new Nota("ingles",5));
    notas.add(new Nota("fisica",7));
    
    Nota nota= buscarNotaSobresaliente(notas);

    // Estas sentencias nos pueden generar el típico java.lang.NullPointerExcepcion
    System.out.println(nota.getValor());
    System.out.println(nota.getAsignatura());
  }

  public static Nota buscarNotaSobresaliente(List<Nota> notas) {

    Nota nota=null;
    for (Nota unaNota:notas) {

      if (unaNota.getValor()>=9) {
        nota= unaNota;
      }
    }
    
    return nota;
 }
}

Esto se soluciona con un !=null

if (nota!=null) {
      System.out.println(nota.getValor());
      System.out.println(nota.getAsignatura());
    }

O usando la clase Optional:

Optional<Nota> oNota= buscarNotaSobresaliente(notas);
    if (oNota.isPresent()) {
      Nota nota=oNota.get();
      System.out.println(nota.getValor());
      System.out.println(nota.getAsignatura());
    }
    
  }
  public static Optional<Nota> buscarNotaSobresaliente(List<Nota> notas) {
    
    for (Nota unaNota:notas) {
      
      
      if (unaNota.getValor()>=9) {
        return Optional.of(unaNota);
      }
    }
    return Optional.empty();
  
  }

Ejemplo con Optional.of():

public Optional<Capitulo> buscarCapitulo (String nombre)  {
        for (Capitulo c: capitulos) {
            if (c.getNombre().equals("nombre")) {   
                return Optional.of(c);
            }    
        }
        return Optional.empty();
    }

//main...

Optional<Capitulo> busqueda;
busqueda = l.buscarCapitulo("capitulo2");
busqueda.ifPresent((x)->System.out.println(x.getLongitud())); // lambda con ifPresent()

Recordemos que un Optional es un tipo que permite almacenar dos valores (valor concreto/valor nulo).

Entonces los Optionals nos permiten manejar valores que podrían no existir. Esto nos ayuda a reducir la cantidad de excepciones generadas por valores nulos (NullPointerExceptions). 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. Esta clase se ha ido ampliando con todas las posibilidades lógicas/booleanas posibles. más posibilidades

Ejemplo de un método que se utiliza con lambda

Un método muy cómodo de usar de Optional es ifPresentOrElse(), y cómo os imáginais es un if else dependiendo si tiene objeto el optional o no. Sintáxis con el uso de lambda:

public void ifPresentOrElse(Consumer<T> action,
                            Runnable emptyAction)

Ejemplo:

 Optional<Integer> op = Optional.ofNullable(9455); // creamos el Optional
 op.ifPresentOrElse( 
            (value) -> { System.out.println( 
                         "Value is present, its: "
                         + value); }, 
            () -> { System.out.println( 
                         "Value is empty"); }); 

Ejercicio 1

Crear un programa que simula un sistema de registro de usuarios (sin persistencia guardar en colecciones). El programa tendrá las siguientes funcionalidades:

  • Registrar un nuevo usuario con nombre, apellido y correo electrónico.
  • Buscar un usuario por su nombre y apellido.
  • Actualizar el correo electrónico de un usuario existente.
  • Eliminar un usuario existente. Para gestionar la ausencia de valores, utilizaremos la clase Optional.