web-dev-qa-db-fra.com

Utilisation appropriée de Optional.ifPresent ()

J'essaie de comprendre la méthode ifPresent() de l'API Optional dans Java 8.

J'ai une logique simple:

Optional<User> user=...
user.ifPresent(doSomethingWithUser(user.get()));

Mais cela entraîne une erreur de compilation: 

ifPresent(Java.util.functionError:(186, 74) Java: 'void' type not allowed here)

Bien sûr, je peux faire quelque chose comme ça:

if(user.isPresent())
{
  doSomethingWithUser(user.get());
}

Mais c’est exactement comme un contrôle null encombré.

Si je change le code en ceci:

 user.ifPresent(new Consumer<User>() {
            @Override public void accept(User user) {
                doSomethingWithUser(user.get());
            }
        });

Le code devient de plus en plus sale, ce qui me fait penser à revenir à l'ancien chèque null.

Des idées?

55
rayman

Optional<User>.ifPresent() prend un Consumer<? super User> en argument. Vous lui transmettez une expression dont le type est vide. Donc, cela ne compile pas. 

Un consommateur est destiné à être implémenté en tant qu'expression lambda:

Optional<User> user = ...
user.ifPresent(theUser -> doSomethingWithUser(theUser));

Ou encore plus simple, en utilisant une référence de méthode:

Optional<User> user = ...
user.ifPresent(this::doSomethingWithUser);

Ceci est fondamentalement la même chose que

Optional<User> user = ...
user.ifPresent(new Consumer<User>() {
    @Override
    public void accept(User theUser) {
        doSomethingWithUser(theUser);
    }
});

L'idée est que l'appel de la méthode doSomethingWithUser() ne sera exécuté que si l'utilisateur est présent. Votre code exécute l'appel de méthode directement et tente de transmettre son résultat d'annulation à ifPresent().

96
JB Nizet

Outre la réponse de @ JBNizet, mon cas d'utilisation général pour ifPresent consiste à combiner .isPresent() et .get():

Ancienne façon:

Optional opt = getIntOptional();
if(opt.isPresent()) {
    Integer value = opt.get();
    // do something with value
}

Nouvelle façon:

Optional opt = getIntOptional();
opt.ifPresent(value -> {
    // do something with value
})

Ceci, pour moi, est plus intuitif.

8
cst1992

Utilisez flatMap. Si une valeur est présente, flatMap renvoie un flux séquentiel contenant uniquement cette valeur, sinon renvoie un flux vide. Il n’est donc pas nécessaire d’utiliser ifPresent(). Exemple:

list.stream().map(data -> data.getSomeValue).map(this::getOptinalValue).flatMap(Optional::stream).collect(Collectors.toList());
4
Taras Melnyk

Vous devez l'utiliser comme ceci:

user.ifPresent(ClassNameWhereMethodIs::doSomethingWithUser);

Méthode ifPresent() obtient un objet Consumer en tant que paramètre et (from JavaDoc ): "Si une valeur est présente, appelez le consommateur spécifié avec la valeur." Valeur c'est votre variable user.

3
Aleksandr Podkutin

Pourquoi faire simple quand vous pouvez écrire du code compliqué!

En effet, si vous voulez absolument utiliser la classe Optional, le code simple correspond à ce que vous avez déjà écrit ...

if (user.isPresent())
    {
    doSomethingWithUser(user.get());
    }

Ce code présente les avantages d'être 

  1. lisible 
  2. facile au point d'arrêt 
  3. pas compliqué

Ce n'est pas parce que Oracle a ajouté la classe Optional dans Java 8 que cette classe doit être utilisée dans toutes les situations.

1
schlebe