web-dev-qa-db-fra.com

Quand j'ai besoin d'utiliser Optional.orElseGet () sur Optional.orElse ()

J'ai besoin d'explications claires à ce sujet, même si je lis ceci link sur les différences, mais pas de clarté claire. Donc, tout le monde m'explique sur ce sujet en utilisant du code.

7
TVK

Je pense que je commence à comprendre votre question. L'ordre d'exécution avec Optional peut être différent de ce à quoi nous sommes habitués en programmation procédurale (il en va de même pour les flux Java et les autres codes utilisant lambdas).

Je vais utiliser les deux exemples de réponse d’Eugene :

    o1.orElse(new MyObject()); // 1055e4af 

C’est du vieux Java: c’est un appel à orElse() qui prend new MyObject() en argument. Donc, l'argument est évalué en premier et une nouvelle MyObject est créée. Ceci est ensuite passé à orElse(). orElse() cherche à savoir si une valeur est présente dans la Optional; si c'est le cas, il renvoie cette valeur (en rejetant l'objet nouvellement créé); sinon, il retourne l'objet qui lui est donné dans l'argument. C'était l'exemple le plus simple.

    o1.orElseGet(() -> {
        System.out.println("Should I see this");
        return new MyObject();
    });

Encore une fois, nous avons un appel de méthode avec un argument, et encore une fois, l'argument est évalué en premier. Le lambda est créé et transmis uniquement en tant que fournisseur. Le code à l'intérieur de { } n'est pas encore exécuté (vous ne voyez pas non plus de Should I see this dans la sortie d'Eugene). Encore une fois orElseGet cherche à voir s'il y a une valeur présente dans la Optional. Si c'est le cas, la valeur est renvoyée et le fournisseur que nous avons transmis est ignoré. Si ce n’est pas le cas, le fournisseur est appelé, le code dans { } est exécuté pour obtenir la valeur à renvoyer de orElseGet().

Dans le premier cas, on peut dire qu'une MyObject est créée et gaspillée. Dans la seconde une Supplier est créée et gaspillée. En retour, vous obtenez un code sécurisé et un code sécurisé à zéro pointeur dans les deux cas. Donc, très souvent, le choix de votre choix importe peu. Si la création de MyObject est coûteuse ou a des effets secondaires indésirables, vous voudrez bien sûr la deuxième version dans laquelle l’objet est créé uniquement à la demande, sans jamais être perdu. Eugene dans un commentaire mentionne le cas où l'objet renvoyé provient d'un appel à une base de données. Les appels à la base de données prennent généralement suffisamment de temps pour que vous ne souhaitiez pas en faire une sans raison.

29
Ole V.V.

Que diriez-vous d'un exemple:

static class MyObject {
    public MyObject() {
        System.out.println("Creating one..." + this);
    }
}

Et quelques utilisations:

  Optional<MyObject> o1 = Optional.of(new MyObject()); // 7382f612

    o1.orElse(new MyObject()); // 1055e4af 
    o1.orElseGet(() -> {
        System.out.println("Should I see this");
        return new MyObject();
    });

Et quelques sorties:

 Creating one... MyObject@7382f612
 Creating one... MyObject@1055e4af

Dans le cas où Optional a une valeur ; orElse est toujours appelé mais n'est pas utilisé. orElseGet n’est pas appelé.

Considérons le cas lorsque la création de l'objet est coûteuse; lequel utiliserez-vous?

En fait, il est plus facile de comprendre je pense si vous regardez dans le code:

public T orElseGet(Supplier<? extends T> supplier) {
    return value != null ? value : supplier.get();
}
12
Eugene

Comme indiqué dans la réponse ici , vous pouvez envisager la seconde approche lorsque la ressource requise est coûteuse à obtenir.

// Always get heavy resource
getResource(resourceId).orElse(getHeavyResource()); 

// Get heavy resource when required.
getResource(resourceId).orElseGet(() -> getHeavyResource()) 
1
nxhoaf