|
| 1 | +# Optional |
| 2 | + |
| 3 | +`Optional` es una clase genérica, **cuyo propósito es ser un contenedor para un valor que puede o no ser nulo**. Fue creado por los ingenieros de Java, para abordar el problema o excepción tan conocida la `NullPointerException`. |
| 4 | + |
| 5 | +La documentación oficial de Java dice que este tipo está pensado principalmente para un uso como tipo de retorno de método, bajo condiciones específicas. |
| 6 | + |
| 7 | +`Optional` trata de resolver el problema cuando hay ausencia de resultados o datos y no queremos que esto sea un error. Por ejemplo, no todas las personas tienen 2o apellido. Esto sería válido para un optional, pero por ejemplo todo el mundo tenemos fecha de nacimiento, esto si que es un error. |
| 8 | + |
| 9 | +## Crear una instancia de `Optional` |
| 10 | + |
| 11 | +`Optional` es una clase genérica que se declara como cualquier otra, indicando el tipo. Aunque, no se puede construir un `Optional`. En su lugar, se usa uno de sus métodos estáticos: `empty`, `of` or `ofNullable`. |
| 12 | + |
| 13 | + |
| 14 | + |
| 15 | +### Ejemplo con `Optional.of` |
| 16 | + |
| 17 | +```java |
| 18 | +Student s = new Student("Patricia", 32, LocalDate.now()); |
| 19 | +Optional<Student> op = Optional.of(s); |
| 20 | +System.out.println("Empty: " + op.isEmpty() + " Present: " + op.isPresent()); |
| 21 | +``` |
| 22 | + |
| 23 | +Output |
| 24 | +>Optional[Patricia,32,2023-10-15] |
| 25 | +
|
| 26 | +>Empty: false Present: true |
| 27 | +
|
| 28 | +Hay que tener cuidado con Optional.of(object), ya que si lo usamos y puede llegar un valor `null`, dará una excepción `NullPointerException`: |
| 29 | + |
| 30 | +```java |
| 31 | +Student s = null; |
| 32 | +Optional<Student> op = Optional.of(s); |
| 33 | +System.out.println(op); |
| 34 | +System.out.println("Empty: " + op.isEmpty() + " Present: " + op.isPresent()); |
| 35 | +``` |
| 36 | + |
| 37 | +Output |
| 38 | +>`NullPointerException` |
| 39 | +
|
| 40 | +Por tanto, no habremos solucionado el problema, en vez de eso, debemos usar el método Optional.ofNullable(object), que si el objeto que se pasa es `null`, devolverá un `Optional` vacío. |
| 41 | + |
| 42 | +```java |
| 43 | +Student s = null; |
| 44 | +Optional<Student> op = Optional.ofNullable(s); |
| 45 | +System.out.println(op); |
| 46 | +System.out.println("Empty: " + op.isEmpty() + " Present: " + op.isPresent()); |
| 47 | +``` |
| 48 | + |
| 49 | +Output |
| 50 | +>Optional.empty |
| 51 | +
|
| 52 | +>Empty: true Present: false |
| 53 | +
|
| 54 | +{== |
| 55 | + |
| 56 | +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. |
| 57 | + |
| 58 | +==} |
| 59 | + |
| 60 | +## Cómo obtener el objeto o valor del `Optional` |
| 61 | + |
| 62 | +El tipo `Optional` tiene un método `get()`, que devuelve el valor. |
| 63 | + |
| 64 | +```java |
| 65 | +Student student = new Student("Patricia", 32, LocalDate.now()); |
| 66 | +Optional<Student> op = Optional.ofNullable(student); |
| 67 | +System.out.println(op.get()); |
| 68 | +System.out.println("Empty: " + op.isEmpty() + " Present: " + op.isPresent()); |
| 69 | +``` |
| 70 | + |
| 71 | +Output |
| 72 | +>Patricia,32,2023-10-15 |
| 73 | +
|
| 74 | +>Empty: false Present: true |
| 75 | +
|
| 76 | +En el ejemplo anterior, ha funcionado correctamente, hemos obtenido el objeto Student al hacer op.get(). |
| 77 | +Veamos que pasa, cuando `Optional.ofNullable()` devuelve un optional vacío: |
| 78 | + |
| 79 | +```java |
| 80 | +Student studentNull = null; |
| 81 | +Optional<Student> op = Optional.ofNullable(studentNull); |
| 82 | +System.out.println(op.get()); |
| 83 | +System.out.println("Empty: " + op.isEmpty() + " Present: " + op.isPresent()); |
| 84 | +``` |
| 85 | + |
| 86 | +Output |
| 87 | +>Exception in thread "main" java.util.NoSuchElementException: No value present |
| 88 | +
|
| 89 | +El código anterior nos lanza una excepción porque **sólo podemos llamar al método get() si el método isPresent es verdadero, es decir, si tengo valor**. Para corregir el error tendríamos que realizar lo siguiente: |
| 90 | + |
| 91 | +```java |
| 92 | +Student studentNull = null; |
| 93 | +Optional<Student> op = Optional.ofNullable(studentNull); |
| 94 | +if (op.isPresent()) { |
| 95 | + System.out.println(op.get()); |
| 96 | +} |
| 97 | + |
| 98 | +// también puedes hacerlo en una sola línea de código |
| 99 | +op.ifPresent(System.out::println); |
| 100 | +``` |
| 101 | +Ahora vemos que no imprime nada porque isPresent() devuelve false, ya que optional es vacío. Si queremos mostrar algo cuando tengamos un Optional vacío, podemos usar el método `ifPresentOrElse`: |
| 102 | + |
| 103 | +```java |
| 104 | +Student studentNull = null; |
| 105 | +Optional<Student> op = Optional.ofNullable(studentNull); |
| 106 | +op.ifPresentOrElse(System.out::println, ()-> System.out.println("empty object")); |
| 107 | +``` |
| 108 | + |
| 109 | +El método ifPresentOrElse, recibe un `Consumer`, que es si el objeto no está vacío, y un `Runnable` que se llamará si está vacío. |
| 110 | +Como `Runnable` es una interfaz funcional, podemos usar lambda para implementar el método `run`, que será la acción que se realice si el objeto `Optional` es vacío. |
| 111 | + |
| 112 | +Output |
| 113 | +>empty object |
0 commit comments