web-dev-qa-db-fra.com

Comment exécuter la logique sur Facultatif s'il n'est pas présent?

Je souhaite remplacer le code suivant à l'aide de Java8 Optional:

public Obj getObjectFromDB() {
    Obj obj = dao.find();
    if (obj != null) {
        obj.setAvailable(true);
    } else {
        logger.fatal("Object not available");
    }

    return obj;
}

Le pseudocode suivant ne fonctionne pas car il n'y a pas de méthode orElseRun, mais il illustre de toute façon mon objectif:

public Optional<Obj> getObjectFromDB() {
    Optional<Obj> obj = dao.find();
    return obj.ifPresent(obj.setAvailable(true)).orElseRun(logger.fatal("Object not available"));
}
62
membersound

Avec Java 9 ou supérieur, ifPresentOrElse est probablement ce que vous voulez:

Optional<> opt = dao.find();

opt.ifPresentOrElse(obj -> obj.setAvailable(true),
                    () -> logger.error("…"));

Currying en utilisant vavr ou similaire pourrait obtenir un code encore plus ordonné, mais je n'ai pas encore essayé.

91
Andreas

Je ne pense pas que vous puissiez le faire en une seule déclaration. Mieux faire:

if (!obj.isPresent()) {
    logger.fatal(...);   
} else {
    obj.get().setAvailable(true);
}
return obj;
33
Konstantin Yovkov

Vous devrez diviser cela en plusieurs déclarations. Voici un moyen de le faire:

if (!obj.isPresent()) {
  logger.fatal("Object not available");
}

obj.ifPresent(o -> o.setAvailable(true));
return obj;

Une autre façon (éventuellement trop élaborée) consiste à utiliser map:

if (!obj.isPresent()) {
  logger.fatal("Object not available");
}

return obj.map(o -> {o.setAvailable(true); return o;});

Si obj.setAvailable renvoie commodément obj, vous pouvez simplement utiliser le deuxième exemple pour:

if (!obj.isPresent()) {
  logger.fatal("Object not available");
}

return obj.map(o -> o.setAvailable(true));
10
Duncan Jones

Pour Java 8 Spring propose ifPresentOrElse dans "Méthodes utilitaires permettant de travailler avec Optionals" pour atteindre vos objectifs. Exemple serait:

import static org.springframework.data.util.Optionals.ifPresentOrElse;    

ifPresentOrElse(dao.find(), obj -> obj.setAvailable(true), () -> logger.fatal("Object not available"));
9
Cmyker

Tout d’abord, votre dao.find() devrait soit renvoyer un Optional<Obj> ou vous devrez en créer un.

par exemple.

Optional<Obj> = dao.find();

ou vous pouvez le faire vous-même comme:

Optional<Obj> = Optional.ofNullable(dao.find());

celui-ci retournera Optional<Obj> s'il est présent ou Optional.empty() s'il n'est pas présent.

Alors maintenant passons à la solution,

public Obj getObjectFromDB() {
   return Optional.ofNullable(dao.find()).flatMap(ob -> {
            ob.setAvailable(true);
            return Optional.of(ob);    
        }).orElseGet(() -> {
            logger.fatal("Object not available");
            return null;
        });
    }

C'est la doublure que vous recherchez :)

9
Hasasn

est une méthode .orElseRun, mais elle s’appelle .orElseGet, le problème est que, contrairement à .map, .isPresent ne renvoie pas un Optional<Obj>.

Si vous voulez vraiment faire cela en une seule déclaration c'est possible:

public Obj getObjectFromDB() {
    return dao.find()
        .map( obj -> { 
            obj.setAvailable(true);
            return Optional.of(obj); 
         })
        .orElseGet( () -> {
            logger.fatal("Object not available"); 
            return Optional.empty();
    });
}

Mais c’est encore plus difficile que ce que vous aviez auparavant.

5
UTF_or_Death

J'ai pu proposer deux solutions "une ligne", par exemple:

    obj.map(o -> (Runnable) () -> o.setAvailable(true))
       .orElse(() -> logger.fatal("Object not available"))
       .run();

ou

    obj.map(o -> (Consumer<Object>) c -> o.setAvailable(true))
       .orElse(o -> logger.fatal("Object not available"))
       .accept(null);

ou

    obj.map(o -> (Supplier<Object>) () -> {
            o.setAvailable(true);
            return null;
    }).orElse(() () -> {
            logger.fatal("Object not available")
            return null;
    }).get();

Cela n'a pas l'air bien, quelque chose comme orElseRun serait beaucoup mieux, mais je pense que l'option avec Runnable est acceptable si vous voulez vraiment une solution en une seule ligne.

1
erkfel

Vous avez besoin de Optional.isPresent () et orElse () . Votre extrait ne fonctionnera pas car il ne renverra rien s’il n’est pas présent.

Le point de option est de le renvoyer à partir de la méthode.

0
NimChimpsky