Java opcional - orElse () vs orElseGet ()

1. Introducción

La API de Opcional generalmente tiene dos métodos que pueden causar confusión: orElse () y orElseGet () .

En este tutorial rápido, veremos la diferencia entre esos dos y exploraremos cuándo usar cada uno.

2. Firmas

Primero comencemos con lo básico mirando sus firmas:

public T orElse(T other) public T orElseGet(Supplier other)

Claramente, OrElse () toma cualquier parámetro de un tipo T , mientras que orElseGet () acepta una interfaz funcional de tipo Proveedor que devuelve un objeto de tipo T .

Ahora, basado en sus Javadocs:

  • orElse () : devuelve el valor si está presente; de ​​lo contrario, devuelve otro
  • orElseGet (): devuelve el valor si está presente; de ​​lo contrario, invoca otro y devuelve el resultado de su invocación

3. Diferencias

Es fácil confundirse un poco con estas definiciones simplificadas, así que profundicemos un poco más y veamos algunos escenarios de uso reales.

3.1. si no()

Suponiendo que tenemos nuestro registrador configurado correctamente, comencemos escribiendo un código simple:

String name = Optional.of("baeldung") .orElse(getRandomName());

Tenga en cuenta que getRandomName () es un método que devuelve un nombre aleatorio de una lista de nombres:

public String getRandomName() { LOG.info("getRandomName() method - start"); Random random = new Random(); int index = random.nextInt(5); LOG.info("getRandomName() method - end"); return names.get(index); }

Al ejecutar nuestro código, encontraremos los siguientes mensajes impresos en la consola:

getRandomName() method - start getRandomName() method - end

El nombre de la variable contendrá "baeldung" al final de la ejecución del código.

Con él, podemos inferir fácilmente que el parámetro de orElse () se evalúa incluso cuando se tiene un Opcional no vacío .

3.2. orElseGet ()

Ahora, intentemos escribir código similar usando orElseGet () :

String name = Optional.of("baeldung") .orElseGet(() -> getRandomName());

El código anterior no invocará el método getRandomName () .

Recuerde (del Javadoc) que el método S upplier que se pasa como argumento solo se ejecuta cuando no hay un valor opcional .

El uso de orElseGet () para nuestro caso, por lo tanto, nos ahorrará algo de tiempo en el cálculo de un nombre aleatorio .

4. Medir el impacto en el desempeño

Ahora, para comprender también las diferencias en el rendimiento, usemos JMH y veamos algunos números reales:

@Benchmark @BenchmarkMode(Mode.AverageTime) public String orElseBenchmark() { return Optional.of("baeldung").orElse(getRandomName()); }

Y orElseGet () :

@Benchmark @BenchmarkMode(Mode.AverageTime) public String orElseGetBenchmark() { return Optional.of("baeldung").orElseGet(() -> getRandomName()); }

Al ejecutar nuestros métodos de referencia, obtenemos:

Benchmark Mode Cnt Score Error Units orElseBenchmark avgt 20 60934.425 ± 15115.599 ns/op orElseGetBenchmark avgt 20 3.798 ± 0.030 ns/op

Como podemos ver, el impacto en el rendimiento podría ser sustancial incluso para un escenario de caso de uso tan simple.

Sin embargo, los números anteriores pueden variar ligeramente, oElseGet () ha superado claramente a orElse () para nuestro ejemplo particular.

Después de todo, orElse () implica el cálculo del método getRandomName () para cada ejecución.

5. ¿Qué es importante?

Aparte de los aspectos de desempeño, otros factores que vale la pena considerar incluyen:

  • ¿Y si el método ejecutara alguna lógica adicional? Por ejemplo, hacer algunas inserciones o actualizaciones de bases de datos
  • Incluso cuando asignamos un objeto al parámetro orElse () :
    String name = Optional.of("baeldung").orElse("Other")

    todavía estamos creando un objeto "Otro" sin ningún motivo

Y es por eso que es importante para nosotros tomar una decisión cuidadosa entre orElse () y orElseGet () dependiendo de nuestras necesidades; de forma predeterminada, tiene más sentido usar orElseGet () cada vez, a menos que el objeto predeterminado ya esté construido y sea accesible directamente .

6. Conclusión

En este artículo, hemos aprendido los matices entre los métodos Optional orElse () y OrElseGet () . También notamos cómo a veces conceptos tan simples pueden tener un significado más profundo.

Como siempre, el código fuente completo se puede encontrar en Github.