|
| 1 | +package com.platzi.functional._14_optionals; |
| 2 | + |
| 3 | +import java.util.Arrays; |
| 4 | +import java.util.List; |
| 5 | +import java.util.Optional; |
| 6 | + |
| 7 | +public class Optionals { |
| 8 | + /* |
| 9 | + * La clase Optional nos ayuda en java 8 a resolver un problema comun en Java: null |
| 10 | + * Con Optional tendremos la posibilidad de operar sobre una clase que nos protege del infame NPE |
| 11 | + * |
| 12 | + * La idea de Optional es que previo a hacer una operacion, se haga una validacion dentro de |
| 13 | + * el Optional para evitar problemas. |
| 14 | + */ |
| 15 | + static Optional<String> ejemplos() { |
| 16 | + //La clase optional nos ofrece diferentes maneras de crear un optional segun los datos que tengamos |
| 17 | + |
| 18 | + //El primero de ellos es crear un Optional de un dato que SI tenemos: |
| 19 | + Optional<String> optional = Optional.of("Java 8"); |
| 20 | + |
| 21 | + //Si no estamos seguros del valor que pondremos en el Optional, podemos usar ofNullable: |
| 22 | + optional = Optional.ofNullable(uknownResult()); |
| 23 | + |
| 24 | + //Y si lo que queremos es evitar devolver un null pero no tenemos un valor para regresar, |
| 25 | + //podemos usar simplemente: |
| 26 | + return Optional.empty(); |
| 27 | + } |
| 28 | + |
| 29 | + |
| 30 | +// |
| 31 | +// |
| 32 | +// |
| 33 | +// |
| 34 | + |
| 35 | + static void obtenerUnDato() { |
| 36 | + Optional<String> optional = Optional.ofNullable(uknownResult()); |
| 37 | + |
| 38 | + //Una vez que tenemos un optional, obtener el dato puede ser tan simple como: |
| 39 | + String dato = optional.get(); |
| 40 | + |
| 41 | + |
| 42 | + //Sin embargo, eso nos provoca el mismo problema que tratamos de solucionar, |
| 43 | + //pues si el dato es null, `get` nos devolera un null. |
| 44 | + |
| 45 | + |
| 46 | + |
| 47 | + //Podemos entonces, checar la presencia de dato: |
| 48 | + if (optional.isPresent()) { |
| 49 | + //Pero esto es muy similar a checar si el dato es null. |
| 50 | + dato = optional.get(); |
| 51 | + } |
| 52 | + |
| 53 | + |
| 54 | + |
| 55 | + //Hagamoslo de manera mas funcional: |
| 56 | + dato = optional.orElse(""); |
| 57 | + |
| 58 | + |
| 59 | + //Y en caso de que nuestro dato sea muy complejo: |
| 60 | + dato = optional.orElseGet(Optionals::complexFunction); |
| 61 | + |
| 62 | + |
| 63 | + //O con una lambda: |
| 64 | + dato = optional.orElseGet(() -> /*Cosas magicas para generar el dato*/ ""); |
| 65 | + |
| 66 | + |
| 67 | + |
| 68 | + //Y esta es la parte donde entendemos que optional tiene mas poderes que validar contra un null. |
| 69 | + |
| 70 | + |
| 71 | + |
| 72 | + //No solo eso, Optional nos permite operar el dato en caso de que este presente: |
| 73 | + optional.ifPresent(System.out::println); |
| 74 | + optional.ifPresent(s -> someComplexOperation(s)); |
| 75 | + |
| 76 | + |
| 77 | + |
| 78 | + //Incluso hacer operaciones para generar nuevos optionals segun sea necesario: |
| 79 | + Optional<String> subOptional = optional.filter(String::isEmpty); |
| 80 | + |
| 81 | + |
| 82 | + |
| 83 | + //O transformar el dato: |
| 84 | + Optional<Integer> integerOptional = optional.map(s -> s.length() * 2); |
| 85 | + |
| 86 | + |
| 87 | + |
| 88 | + //Es importante mencionar que Optional no ejecutara ninguna de estas funciones |
| 89 | + //en casos donde el dato no existe (null, empty() ). Asi que es seguro. |
| 90 | + |
| 91 | + //Optional nos da un acercamiento hacia un concepto que en FP se conoce como Monad |
| 92 | + } |
| 93 | + |
| 94 | + |
| 95 | + /** |
| 96 | + * Ejemplo al codigo antes de Optional |
| 97 | + */ |
| 98 | + static String antesDeOptional(List<String> names) { |
| 99 | + //Antes de optional, era comun tener un pequeño `if` validando la presencia de valor |
| 100 | + // en los argumentos de nuestros metodos |
| 101 | + if (names == null) { |
| 102 | + |
| 103 | + //Y una mala practica era, en error o ausencia de datos, retornar un null. |
| 104 | + //Esto es una mala practica porque es una manera de evadir operaciones. Forzando que tambien |
| 105 | + //el codigo que invoco nuestra funcion tenga que validar si el resultado es null. |
| 106 | + return null; |
| 107 | + } |
| 108 | + |
| 109 | + return Arrays.toString(names.toArray()); |
| 110 | + } |
| 111 | + |
| 112 | +// |
| 113 | +// |
| 114 | +// |
| 115 | +// |
| 116 | +// |
| 117 | +// |
| 118 | +// |
| 119 | +// |
| 120 | +// |
| 121 | +// |
| 122 | + |
| 123 | +// |
| 124 | +// |
| 125 | +// |
| 126 | +// |
| 127 | +// |
| 128 | +// |
| 129 | + |
| 130 | + /** |
| 131 | + * Con la clase optional le damos una mayor seguridad a quien ejecuta nuestro codigo, |
| 132 | + * pues le ahorramos operaciones de validacion y puede decidir que hacer con los datos |
| 133 | + * de una manera mas directa. |
| 134 | + */ |
| 135 | + static Optional<String> conOptional(List<String> names) { |
| 136 | + if (names == null || names.isEmpty()) { |
| 137 | + return Optional.empty(); |
| 138 | + } |
| 139 | + |
| 140 | + return Optional.of(Arrays.toString(names.toArray())); |
| 141 | + } |
| 142 | + |
| 143 | + |
| 144 | + // |
| 145 | +// |
| 146 | +// |
| 147 | +// |
| 148 | +// |
| 149 | +// |
| 150 | +// |
| 151 | +// |
| 152 | +// |
| 153 | +// |
| 154 | +// |
| 155 | +// |
| 156 | + |
| 157 | + /** |
| 158 | + * Funcion usando ambos casos: |
| 159 | + */ |
| 160 | + static void outside() { |
| 161 | + //Invocando a un metodo que no sabemos que devuelve: |
| 162 | + String directResult = antesDeOptional(null); |
| 163 | + if (directResult != null) { |
| 164 | + directResult = directResult.replace("Sierisimo", "Sinuhe"); |
| 165 | + } |
| 166 | + |
| 167 | + //Con optional: |
| 168 | + Optional<String> optionalResult = conOptional(null); |
| 169 | + |
| 170 | + directResult = optionalResult |
| 171 | + .map(s -> s.replace("Sierisimo", "Sinuhe")) |
| 172 | + .orElse("Sinuhe"); |
| 173 | + |
| 174 | + //Incluso podriamos hacer chaining directo: |
| 175 | + conOptional(null).filter(s -> !s.isEmpty()) |
| 176 | + .map(s -> s.replace("@Sierisimo", "Sinuhe")) |
| 177 | + .orElse("Sinuhe"); |
| 178 | + |
| 179 | + //Como vemos, optional nos facilita operar sobre datos |
| 180 | + } |
| 181 | + |
| 182 | + // |
| 183 | +// |
| 184 | +// |
| 185 | +// |
| 186 | +// |
| 187 | +// |
| 188 | +// |
| 189 | +// |
| 190 | +// |
| 191 | +// |
| 192 | +// |
| 193 | + static String uknownResult() { |
| 194 | + return null; |
| 195 | + } |
| 196 | + |
| 197 | + static String complexFunction() { |
| 198 | + return "Complex Result"; |
| 199 | + } |
| 200 | + |
| 201 | + static void someComplexOperation(String s) { |
| 202 | + |
| 203 | + } |
| 204 | +} |
0 commit comments