Saltar a contenido

🎁 Optional en Java

🧠 1. ¿Qué es Optional?

Optional es una clase que representa un valor que puede estar presente o no.

👉 Es decir: evita trabajar directamente con null.

Optional<String> nombre = Optional.of("Ana");

o

Optional<String> nombre = Optional.empty();

❗ 2. ¿Por qué existe?

Antes de Optional, era muy común esto:

String nombre = obtenerNombre();

if (nombre != null) {
    System.out.println(nombre.toUpperCase());
}

Problema 👉 riesgo de NullPointerException.


✅ Con Optional

Optional<String> nombre = obtenerNombre();

nombre.ifPresent(n -> System.out.println(n.toUpperCase()));

✔ Más seguro
✔ Más claro
✔ Evita errores típicos


La primera regla para los desarrolladores que utilizan Optional, es que cualquier método que devuelva un Optional, nunca debe devolver null. En su lugar, debería devolver un optional vacío.


📦 3. Cómo crear un Optional

🔹 of()

Crea un Optional con un valor seguro, que sabemos que no es null.

Optional<String> nombre = Optional.of("Ana");

//Esto da error
Optional<String> nombre = Optional.of(null); // NullPointerException

⚠️ Si pasas null, lanza excepción.


🔹 ofNullable()

Crea un Optional que puede tener valor o estar vacío.

Optional<String> nombre = Optional.ofNullable(null);//Optional vacío

Si lo creas con valor null, es como hacer Optional.empty().

✔ Permite null
✔ Si es null → Optional vacío


🔹 empty()

Crea un Optional vacío. No contiene nada.

Optional<String> nombre = Optional.empty();
String nombre = obtenerNombre();

Optional<String> optNombre = Optional.ofNullable(nombre);

Aquí usamos ofNullable() porque no sabemos si obtenerNombre() devolverá un nombre o null.


🔍 4. Métodos más importantes

👀 isPresent()

Comprueba si un Optional tiene un valor dentro.

Optional<String> nombre = ...;

if (nombre.isPresent()) {
    System.out.println(nombre.get());
}

⚠️ Poco recomendado (parecido a usar null)


🎯 ifPresent()

Ejecuta una acción solo si el Optional tiene valor. Si está vacío, no hace nada.

Optional<String> nombre = ...;

nombre.ifPresent(n -> System.out.println(n));

✔ Ejecuta solo si hay valor


🎁 orElse()

Devuelve el valor del Optional si existe. Y si está vacío, devuelve un valor por defecto.

Optional<String> nombre = ...;

String resultado = nombre.orElse("Desconocido");

✔ Devuelve valor o uno por defecto


orElseGet()

Hace casi lo mismo que orElse(): devuelve el valor del Optional si existe, y si está vacío, genera un valor por defecto.

La diferencia está en el valor por defecto, en orElse() ya está escrito, en orElseGet() el valor por defecto se genera con un lambda solo si hace falta. Por tanto, es más eficiente.

String resultado = nombre.orElseGet(() -> "Generado");

💥 orElseThrow()

Devuelve el valor del Optional si existe. Pero si está vacío, lanza una excepción.

String resultado = nombre.orElseThrow();// lanza NoSuchElementException

//También puedes indicar tu propia excepción:
String resultado = nombre.orElseThrow(
        () -> new IllegalArgumentException("No hay nombre")
);

✔ Lanza excepción si está vacío


🔄 5. Transformar valores


🔹 map()

Optional<String> nombre = Optional.of("ana");

Optional<String> mayus = nombre.map(String::toUpperCase);

✔ Transforma si hay valor
✔ Si no hay → sigue vacío


🔹 flatMap()

Se usa cuando ya tienes Optional dentro de Optional.

Optional<Optional<String>> raro = Optional.of(Optional.of("hola"));

Con flatMap:

Optional<String> limpio = raro.flatMap(x -> x);

🔗 6. Relación con Streams

Muchos métodos de Streams devuelven Optional:

Optional<Integer> max = lista.stream().max(Integer::compareTo);

👉 Porque puede que no haya resultado


🧪 7. Ejemplos prácticos


✅ Ejemplo 1: buscar usuario

Optional<String> buscarUsuario(int id) {
    if (id == 1) return Optional.of("Ana");
    return Optional.empty();
}

Uso:

buscarUsuario(1).ifPresent(System.out::println);

✅ Ejemplo 2: valor por defecto

String nombre = buscarUsuario(2).orElse("Invitado");

✅ Ejemplo 3: encadenar operaciones

Optional<String> nombre = Optional.of("ana");

String resultado = nombre
        .map(String::toUpperCase)
        .orElse("VACÍO");

🧨 8. Errores típicos


❌ Usar get() sin comprobar

nombre.get(); // peligro

❌ Usar Optional como variable normal

Optional<String> nombre = Optional.of("Ana");
System.out.println(nombre); // ❌

✔ Usa métodos de Optional


❌ Abusar de Optional

No se usa:

  • En atributos de clases (normalmente)
  • Como parámetro
  • Para todo

🆚 9. Optional vs null

null Optional
Puede romper el programa Más seguro
Difícil de leer Más claro
Propenso a errores Evita NPE

🧠 10. Cuándo usar Optional

✅ Úsalo cuando:

✔ Un método puede no devolver valor
✔ Trabajas con Streams
✔ Quieres evitar null


❌ No lo uses cuando:

❌ Siempre hay valor
❌ En variables simples
❌ Para complicar código sencillo


🧩 11. Ejercicio rápido

Dado:

Optional<String> nombre = Optional.ofNullable(null);

👉 Muestra "Sin nombre" si está vacío.


✅ 12. Resumen

  • Optional evita trabajar con null
  • Representa valor presente o ausente
  • Tiene métodos seguros para trabajar con él
  • Muy usado con Streams
  • No sustituye todo, solo casos concretos

💡 Idea clave:

Optional no es obligatorio… pero bien usado, evita muchos errores.