ejemplo baeldung java java-8 optional

java - baeldung - Diferencia entre `Opcional.oElse()` y `Opcional.oElseGet()`



optional java ejemplo (7)

Estoy tratando de entender la diferencia entre los métodos Optional<T>.orElse() y Optional<T>.orElseGet() .

La descripción del método orElse() es "Devuelve el valor si está presente, de lo contrario devuelve otro".

Mientras que la descripción del método orElseGet() es "Devuelve el valor si está presente, de lo contrario invoca a otro y devuelve el resultado de esa invocación"

El método orElseGet() toma una interfaz funcional de proveedor, que esencialmente no toma ningún parámetro y devuelve T

¿En qué situación necesitarías usar orElseGet() ? Si tiene un método T myDefault() ¿por qué no haría optional.orElse(myDefault()) lugar de optional.orElseGet(() -> myDefault()) ?

No parece que orElseGet() la ejecución de la expresión lambda en algún momento posterior o algo así, ¿cuál es el punto? (Pensé que sería más útil si devolviera un Optional<T> más seguro cuyo get() nunca arroja una NoSuchElementException y isPresent() siempre devuelve verdadero ... pero evidentemente no lo es, solo devuelve T como o orElse() ).

¿Hay alguna otra diferencia que me estoy perdiendo?


Diría que la mayor diferencia entre orElse y orElseGet produce cuando queremos evaluar algo para obtener el nuevo valor en la condición else .

Considere este simple ejemplo:

// oldValue is String type field that can be NULL String value; if (oldValue != null) { value = oldValue; } else { value = apicall().value; }

Ahora transformemos el ejemplo anterior para usar Optional junto con orElse ,

// oldValue is Optional type field String value = oldValue.orElse(apicall().value);

Ahora transformemos el ejemplo anterior para usar Optional junto con orElseGet ,

// oldValue is Optional type field String value = oldValue.orElseGet(() -> apicall().value);

Cuando se invoca orElse , el valor apicall().value Se evalúa y se pasa al método. Mientras que, en el caso de orElseGet la evaluación solo ocurre si oldValue está vacío. orElseGet permite una evaluación perezosa.


El siguiente ejemplo debería demostrar la diferencia:

String destroyTheWorld() { // destroy the world logic return "successfully destroyed the world"; } Optional<String> opt = Optional.empty(); // we''re dead opt.orElse(destroyTheWorld()); // we''re safe opt.orElseGet(() -> destroyTheWorld());

La respuesta también aparece en los documentos.

Optional<T>.orElseGet() :

Devuelva el valor si está presente, de lo contrario invoque a otro y devuelva el resultado de esa invocación.

No se invocará al Supplier si se presenta el Optional . mientras,

Optional<T>.orElse() :

Devuelve el valor si está presente, de lo contrario devuelve otro

Si other es un método que devuelve una cadena, se invocará, pero su valor no se devolverá en caso de que el Optional exista.


La diferencia es bastante sutil y si no prestas mucha atención, la seguirás usando de manera incorrecta.

La mejor manera de entender la diferencia entre orElse() y orElseGet() es que orElse() siempre se ejecutará si el Optional<T> es nulo o no , pero orElseGet() solo se ejecutará cuando el Optional<T> sea nulo .

El significado del diccionario de orElse es : - ejecuta la parte cuando algo no está presente, pero aquí contradice, mira el siguiente ejemplo:

String destroyTheWorld() { // destroy the world logic return "successfully destroyed the world"; } Optional<String> opt = Optional.empty(); // we''re dead opt.orElse(destroyTheWorld()); // we''re safe opt.orElseGet(() -> destroyTheWorld());

Salida: nonEmptyOptional no es NULL, todavía estoy siendo ejecutado

import java.util.Optional; // one class needs to have a main() method public class Test { public String orelesMethod() { System.out.println("in the Method"); return "hello"; } public void test() { String value; value = Optional.<String>ofNullable("test").orElseGet(this::orelesMethod); System.out.println(value); value = Optional.<String>ofNullable("test").orElse(orelesMethod()); System.out.println(value); } // arguments are passed using the text field below this editor public static void main(String[] args) { Test test = new Test(); test.test(); } }

Salida : emptyOptional es NULL, estoy en ejecución, es normal según el diccionario

Para orElseGet() , el método funciona según el significado del diccionario, la parte orElseGet() se ejecutará solo cuando el Opcional sea nulo .

Puntos de referencia :

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

Observaciones : orElseGet() ha superado claramente a orElse() en nuestro ejemplo particular.

Espero que aclare las dudas de personas como yo que quieren el ejemplo básico muy básico :)


Llegué aquí por el problema que Kudo mencionó.

Estoy compartiendo mi experiencia por los demás.

o orElse , o orElseGet , esa es la pregunta:

static String B() { System.out.println("B()..."); return "B"; } public static void main(final String... args) { System.out.println(Optional.of("A").orElse(B())); System.out.println(Optional.of("A").orElseGet(() -> B())); }

huellas dactilares

B()... A A

orElse evalúa el valor de B () de manera interdependiente del valor de lo opcional. Por lo tanto, orElseGet es vago.


Respuesta corta:

  • orElse () siempre llamará a la función dada, lo desee o no, independientemente del valor de Optional.isPresent()
  • orElseGet () solo llamará a la función dada cuando el Optional.isPresent() == false

En el código real, es posible que desee considerar el segundo enfoque cuando el recurso requerido es costoso de obtener .

// Always get heavy resource getResource(resourceId).orElse(getHeavyResource()); // Get heavy resource when required. getResource(resourceId).orElseGet(() -> getHeavyResource())

Para más detalles, considere el siguiente ejemplo con esta función:

public Optional<String> findMyPhone(int phoneId)

La diferencia es la siguiente:

X : buyNewExpensivePhone() called +——————————————————————————————————————————————————————————————————+——————————————+ | Optional.isPresent() | true | false | +——————————————————————————————————————————————————————————————————+——————————————+ | findMyPhone(int phoneId).orElse(buyNewExpensivePhone()) | X | X | +——————————————————————————————————————————————————————————————————+——————————————+ | findMyPhone(int phoneId).orElseGet(() -> buyNewExpensivePhone()) | | X | +——————————————————————————————————————————————————————————————————+——————————————+

Cuando optional.isPresent() == false , no hay diferencia entre dos formas. Sin embargo, cuando optional.isPresent() == true , o orElse() siempre llama a la función posterior, lo desee o no.

Finalmente, el caso de prueba utilizado es el siguiente:

Resultado:

------------- Scenario 1 - orElse() -------------------- 1.1. Optional.isPresent() == true Going to a very far store to buy a new expensive phone Used phone: MyCheapPhone 1.2. Optional.isPresent() == false Going to a very far store to buy a new expensive phone Used phone: NewExpensivePhone ------------- Scenario 2 - orElseGet() -------------------- 2.1. Optional.isPresent() == true Used phone: MyCheapPhone 2.2. Optional.isPresent() == false Going to a very far store to buy a new expensive phone Used phone: NewExpensivePhone

Código:

public class TestOptional { public Optional<String> findMyPhone(int phoneId) { return phoneId == 10 ? Optional.of("MyCheapPhone") : Optional.empty(); } public String buyNewExpensivePhone() { System.out.println("/tGoing to a very far store to buy a new expensive phone"); return "NewExpensivePhone"; } public static void main(String[] args) { TestOptional test = new TestOptional(); String phone; System.out.println("------------- Scenario 1 - orElse() --------------------"); System.out.println(" 1.1. Optional.isPresent() == true"); phone = test.findMyPhone(10).orElse(test.buyNewExpensivePhone()); System.out.println("/tUsed phone: " + phone + "/n"); System.out.println(" 1.2. Optional.isPresent() == false"); phone = test.findMyPhone(-1).orElse(test.buyNewExpensivePhone()); System.out.println("/tUsed phone: " + phone + "/n"); System.out.println("------------- Scenario 2 - orElseGet() --------------------"); System.out.println(" 2.1. Optional.isPresent() == true"); // Can be written as test::buyNewExpensivePhone phone = test.findMyPhone(10).orElseGet(() -> test.buyNewExpensivePhone()); System.out.println("/tUsed phone: " + phone + "/n"); System.out.println(" 2.2. Optional.isPresent() == false"); phone = test.findMyPhone(-1).orElseGet(() -> test.buyNewExpensivePhone()); System.out.println("/tUsed phone: " + phone + "/n"); } }


Teniendo en cuenta el siguiente código:

import java.util.Optional; // one class needs to have a main() method public class Test { public String orelesMethod() { System.out.println("in the Method"); return "hello"; } public void test() { String value; value = Optional.<String>ofNullable("test").orElseGet(this::orelesMethod); System.out.println(value); value = Optional.<String>ofNullable("test").orElse(orelesMethod()); System.out.println(value); } // arguments are passed using the text field below this editor public static void main(String[] args) { Test test = new Test(); test.test(); } }

si obtenemos value de esta manera: Optional.<String>ofNullable(null) , no hay diferencia entre orElseGet () y orElse (), pero si obtenemos value de esta manera: Optional.<String>ofNullable("test") , orelesMethod() en orElseGet() no se llamará pero en orElse() se llamará


Tome estos dos escenarios:

Optional<Foo> opt = ... Foo x = opt.orElse( new Foo() ); Foo y = opt.orElseGet( Foo::new );

Si opt no contiene un valor, los dos son equivalentes. Pero si opt contiene un valor, ¿cuántos objetos Foo se crearán?

Ps: por supuesto, en este ejemplo, la diferencia probablemente no sería medible, pero si tiene que obtener su valor predeterminado de un servicio web remoto, por ejemplo, o de una base de datos, de repente se vuelve muy importante.