Différence entre `Optional.orElse ()` et `Optional.orElseGet ()`

J’essaie de comprendre la différence entre les méthodes Optional.orElse() et Optional.orElseGet() .

La description de la méthode orElse() est “Renvoyer la valeur si elle est présente, sinon renvoyer une autre”.

Bien que la description de la méthode orElseGet() soit “Renvoyer la valeur si elle est présente, appelez-en une autre et renvoyez le résultat de cette invocation”.

La méthode orElseGet() utilise une interface fonctionnelle fournisseur, qui ne prend essentiellement aucun paramètre et renvoie T

Dans quelle situation devriez-vous utiliser orElseGet() ? Si vous avez une méthode T myDefault() pourquoi ne pas simplement faire optional.orElse(myDefault()) plutôt que optional.orElseGet(() -> myDefault()) ?

Il ne semble pas que orElseGet() l’exécution de l’expression lambda plus tard ou quelque chose, alors à quoi ça orElseGet() ? (J’aurais pensé que ce serait plus utile si elle retournait une Optional plus sûre. Optional dont get() ne lève jamais une NoSuchElementException et isPresent() retourne toujours true … mais évidemment ce n’est pas le cas, il retourne T like orElse() ).

Y a-t-il une autre différence qui me manque?

Prenez ces deux scénarios:

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

Si opt ne contient pas de valeur, les deux sont en effet équivalentes. Mais si opt contient une valeur, combien d’objects Foo seront créés?

Ps: bien sûr, dans cet exemple, la différence ne serait probablement pas mesurable, mais si vous devez obtenir votre valeur par défaut à partir d’un service Web distant par exemple, ou d’une firebase database, cela devient soudainement très important.

Je suis arrivé ici pour le problème mentionné par Kudo .

Je partage mon expérience pour les autres.

orElse ou orElseGet , telle est la question:

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

estampes

 B()... A A 

Je dirais que la plus grande différence entre orElse et orElseGet vient quand nous voulons évaluer quelque chose pour obtenir la nouvelle valeur dans la condition else .

Considérez cet exemple simple –

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

Maintenant, transformons l’exemple ci-dessus en utilisant Optional avec orElse ,

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

Maintenant, transformons l’exemple ci-dessus en utilisant Optional avec orElseGet ,

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

Lorsque orElse est orElse , la valeur apicall().value Est évaluée et transmise à la méthode. Alors que, dans le cas de orElseGet l’évaluation ne se produit que si oldValue est vide. orElseGet permet une évaluation paresseuse.

Réponse courte:

  • orElse () appellera toujours la fonction donnée, que vous le vouliez ou non, quelle que soit la valeur de Optional.isPresent()
  • orElseGet () appellera uniquement la fonction donnée lorsque Optional.isPresent() == false

Dans le code réel, vous pouvez envisager la deuxième approche lorsque la ressource requirejse est coûteuse .

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

Pour plus de détails, prenez l’exemple suivant avec cette fonction:

 public Optional findMyPhone(int phoneId) 

La différence est comme ci-dessous:

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

Lorsque optional.isPresent() == false , cela ne fait aucune différence entre deux méthodes. Cependant, lorsque optional.isPresent() == true , orElse() appelle toujours la fonction suivante, que vous le vouliez ou non.

Enfin, le cas de test utilisé est le suivant:

Résultat:

 ------------- 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 

Code:

 public class TestOptional { public Optional findMyPhone(int phoneId) { return phoneId == 10 ? Optional.of("MyCheapPhone") : Optional.empty(); } public Ssortingng buyNewExpensivePhone() { System.out.println("\tGoing to a very far store to buy a new expensive phone"); return "NewExpensivePhone"; } public static void main(Ssortingng[] args) { TestOptional test = new TestOptional(); Ssortingng 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"); } } 

Considérant le code suivant:

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

Si nous obtenons une value de cette manière: Optional.ofNullable(null) , il n’y a pas de différence entre orElseGet () et orElse (), mais si nous obtenons une value de cette manière: Optional.ofNullable("test") , orelesMethod() dans orElseGet() ne sera pas appelé mais dans orElse() il sera appelé