Comment exécuter la logique sur facultatif si non présent?

Je souhaite remplacer le code suivant par java8 Optional :

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

Le pseudo- orElseRun suivant ne fonctionne pas car il n’y a pas de méthode orElseRun , mais de toute façon cela illustre mon objective:

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

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

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

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("…")); 

Le curry utilisant vavr ou similaire pourrait avoir un code encore plus précis , mais je n’ai pas encore essayé.

Vous devrez diviser cela en plusieurs déclarations. Voici une façon de le faire:

 if (!obj.isPresent()) { logger.fatal("Object not available"); } obj.ifPresent(o -> o.setAvailable(true)); return obj; 

Une autre façon (éventuellement sur-modifiée) consiste à utiliser la 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 , alors vous pouvez simplement le deuxième exemple:

 if (!obj.isPresent()) { logger.fatal("Object not available"); } return obj.map(o -> o.setAvailable(true)); 

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

par exemple

 Optional = dao.find(); 

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

 Optional = Optional.ofNullable(dao.find()); 

celui-ci retournera Optional 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 le seul paquebot que vous recherchez 🙂

Il y a une méthode .orElseRun , mais elle s’appelle .orElseGet , le problème est que, contrairement à .map , .isPresent ne retourne pas de Optional .

Si vous voulez vraiment faire cela dans une 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 cela est encore plus compliqué que ce que vous aviez auparavant.

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

Le sharepoint facultatif est de le renvoyer de la méthode.

J’ai été en mesure de proposer deux solutions “one line”, par exemple:

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

ou

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

ou

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

Cela ne semble pas très beau, quelque chose comme orElseRun serait beaucoup mieux, mais je pense que cette option avec Runnable est acceptable si vous voulez vraiment une solution à une ligne.

Je suppose que vous ne pouvez pas modifier la méthode dao.find() pour renvoyer une instance de Optional , vous devez donc en créer une appropriée.

Le code suivant devrait vous aider. J’ai créé la classe OptionalAction , qui fournit le mécanisme if-else pour vous.

 public class OptionalTest { public static Optional getObjectFromDb() { // doa.find() DbObject v = find(); // create appropriate Optional Optional object = Optional.ofNullable(v); // @formatter:off OptionalAction. ifPresent(object) .then(o -> o.setAvailable(true)) .elseDo(o -> System.out.println("Fatal! Object not available!")); // @formatter:on return object; } public static void main(Ssortingng[] args) { Optional object = getObjectFromDb(); if (object.isPresent()) System.out.println(object.get()); else System.out.println("There is no object!"); } // find may return null public static DbObject find() { return (Math.random() > 0.5) ? null : new DbObject(); } static class DbObject { private boolean available = false; public boolean isAvailable() { return available; } public void setAvailable(boolean available) { this.available = available; } @Override public Ssortingng toSsortingng() { return "DbObject [available=" + available + "]"; } } static class OptionalAction { public static  IfAction ifPresent(Optional optional) { return new IfAction<>(optional); } private static class IfAction { private final Optional optional; public IfAction(Optional optional) { this.optional = optional; } public ElseAction then(Consumer consumer) { if (optional.isPresent()) consumer.accept(optional.get()); return new ElseAction<>(optional); } } private static class ElseAction { private final Optional optional; public ElseAction(Optional optional) { this.optional = optional; } public void elseDo(Consumer consumer) { if (!optional.isPresent()) consumer.accept(null); } } } }