JavaRush /Blog Java /Random-ES /Pausa para el café #161. Cómo manejar Null en Java usando...

Pausa para el café #161. Cómo manejar Null en Java usando Opcional

Publicado en el grupo Random-ES
Fuente: Medio Este artículo le ayudará a comprender mejor el propósito de Opcional cuando trabaja con código Java. Pausa para el café #161.  Cómo manejar Null en Java usando Opcional - 1Cuando comencé a trabajar con código Java, a menudo me aconsejaban usar Opcional. Pero en ese momento no entendía por qué usar Opcional era mejor que implementar el manejo de valores nulos. En este artículo, quiero compartir con ustedes por qué creo que todos deberíamos usar Opcional más y cómo evitar sobreopcionalizar su código, lo cual es perjudicial para la calidad del código.

¿Qué es opcional?

El parámetro opcional se utiliza para transportar objetos y permitir que varias API manejen referencias nulas . Veamos el fragmento de código:
Coffee coffee = new Coffee();
Integer quantity = coffee.getSugar().getQuantity();
Tenemos una instancia de Coffee en la que obtenemos algo de azúcar de una instancia del objeto Sugar . Si asumimos que el valor de cantidad nunca se estableció en el constructor Coffee , entonces coffee.getSugar().getQuantity() devolverá una NullPointerException . Por supuesto, siempre podemos utilizar las antiguas comprobaciones nulas para solucionar el problema.
Coffee coffee = new Coffee();
Integer quantity = 0;
if (coffee.getSugar() != null) {
  quantity = coffee.getSugar().getQuantity();
}
Ahora todo parece estar bien. Pero al escribir código Java, será mejor que evitemos implementar comprobaciones nulas . Veamos cómo se puede hacer esto usando Opcional.

Cómo crear opcional

Hay tres formas de crear objetos opcionales:
  • of(valor T) : creación de instancias de un objeto opcional no nulo. Tenga en cuenta que el uso de of() para hacer referencia a un objeto nulo generará una NullPointerException .

  • ofNullable(valor T) : crea un valor opcional para un objeto que puede ser nulo.

  • vacío() : crea una instancia opcional que representa una referencia a nulo .

// пример использования Optional.of(T Value)
String name = "foo";
Optional<String> stringExample = Optional.of(name)
// пример использования Optional.ofNullable(T Value)
Integer age = null;
Optional<Integer> integerExample= Optional.ofNullable(age)
// пример использования Optional.empty()
Optional<Object> emptyExample = Optional.empty();
Entonces tienes un objeto opcional. Ahora echemos un vistazo a los dos métodos principales de Opcional:
  • isPresent() : este método le indica si el objeto opcional contiene un valor no nulo.

  • get() : recupera el valor de Opcional con el valor actual. Tenga en cuenta que llamar a get() en un Opcional vacío dará como resultado una NullPointerException .

Tenga en cuenta que si solo usa get() e isPresent() cuando trabaja con Opcional, ¡se está perdiendo algo! Para entender esto, reescribamos el ejemplo anterior con Opcional.

Mejora de la verificación nula con opcional

Entonces, ¿cómo podemos mejorar el código anterior? Con Opcional podemos entender la presencia de un objeto usando isPresent() y recuperarlo usando get() . Comencemos empaquetando el resultado de coffee.getSugar() con Opcional y usando el método isPresent() . Esto nos ayudará a determinar si getSugar() devuelve nulo.
Coffee coffee = new Coffee();
Optional<String> sugar = Optional.ofNullable(coffee.getSugar());
int quantity = 0;
if (sugar.isPresent()) {
  Sugar sugar = sugar.get();
  int quantity = sugar.getQuantity();
}
Al observar este ejemplo, empaquetar el resultado de coffee.getSugar() en Opcional no parece agregar ningún valor, sino que agrega molestias. Podemos mejorar el resultado usando las que considero mis funciones favoritas de la clase Opcional:
  • map(Función<? super T,? extiende U> mapper) : asigna el valor contenido en Opcional a la función proporcionada. Si el parámetro Opcional está vacío, entonces map() devolverá Opcional.empty() .

  • orElse(T other) es una versión "especial" del método get() . Puede obtener el valor contenido en Opcional. Sin embargo, en el caso de un Opcional vacío, esto devolverá el valor pasado al método orElse() .

El método devolverá el valor contenido en la instancia Opcional. Pero si el parámetro Opcional está vacío, lo que significa que no contiene ningún valor, entonces orElse() devolverá el valor pasado a la firma de su método, que se conoce como valor predeterminado.
Coffee coffee = new Coffee();

Integer quantity = Optional.ofNullable(coffee.getSugar())
    .map(it -> it.getQuantity())
    .orElse(0);
Esto es realmente genial, al menos eso creo. Ahora, si en el caso de un valor vacío no queremos devolver el valor predeterminado, entonces debemos lanzar algún tipo de excepción. orElseThrow(Proveedor<? extiende X> excepciónProveedor) devuelve el valor contenido en los parámetros opcionales o genera una excepción si el Opcional está vacío.
Coffee coffee = new Coffee();

Integer quantity = Optional.ofNullable(coffee.getSugar())
  .map(it -> it.getQuantity())
  .orElseThrow(IllegalArgumentException::new);
Como puede ver, Opcional ofrece varias ventajas:
  • comprobaciones nulas de resúmenes
  • proporciona una API para manejar objetos nulos
  • Permite que el enfoque declarativo exprese lo que se está logrando.

Cómo ser efectivo con Opcional

En mi trabajo, uso Opcional como tipo de retorno cuando un método puede devolver un estado "sin resultado". Normalmente lo uso cuando defino tipos de retorno para métodos.
Optional<Coffee> findByName(String name) {
   ...
}
A veces esto no es necesario. Por ejemplo, si tengo un método que devuelve un int , como getQuantity() en la clase Sugar , entonces el método podría devolver 0 si el resultado es nulo para representar "sin cantidad". Ahora bien, sabiendo esto, podemos pensar que el parámetro Azúcar en la clase Café se puede representar como Opcional. A primera vista, esto parece una buena idea ya que, en teoría, no es necesario que el azúcar esté presente en el café. Sin embargo, aquí es donde me gustaría abordar cuándo no utilizar Opcional. Deberíamos evitar el uso de Opcional en los siguientes escenarios:
  • Como tipos de parámetros para POJO , como DTO . Los opcionales no son serializables, por lo que usarlos en un POJO hace que el objeto no sea serializable.

  • Como argumento de método. Si el argumento de un método puede ser nulo , entonces, desde una perspectiva de código puro, pasar nulo sigue siendo preferible a pasar Opcional. Además, puede crear métodos sobrecargados para manejar de forma abstracta la ausencia de un argumento de método nulo.

  • Para representar un objeto de Colección que falta. Las colecciones pueden estar vacías, por lo que se debe utilizar una Colección vacía , como un Conjunto o Lista vacío, para representar una Colección sin valores.

Conclusión

Opcional se ha convertido en una poderosa adición a la biblioteca de Java. Proporciona una manera de manejar objetos que pueden no existir. Por tanto, conviene tenerlo en cuenta a la hora de desarrollar métodos sin caer en la trampa del abuso. Sí, puedes escribir código excelente que implemente comprobaciones y manejo de nulos, pero la comunidad Java prefiere usar Opcional. Comunica de manera efectiva cómo manejar los valores faltantes, es mucho más fácil de leer que las comprobaciones nulas confusas y genera menos errores en el código a largo plazo.
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION