Quiero reemplazar el siguiente código usando java8 Optional
:
public Obj getObjectFromDB() {
Obj obj = dao.find();
if (obj != null) {
obj.setAvailable(true);
} else {
logger.fatal("Object not available");
}
return obj;
}
El siguiente pseudocódigo no funciona porque no hay un orElseRun
método, pero de todos modos ilustra mi propósito:
public Optional<Obj> getObjectFromDB() {
Optional<Obj> obj = dao.find();
return obj.ifPresent(obj.setAvailable(true)).orElseRun(logger.fatal("Object not available"));
}
Optional
siempre como lo indica el parámetro de retorno del método.Respuestas:
Con Java 9 o superior,
ifPresentOrElse
lo más probable es que sea lo que desee:Optional<> opt = dao.find(); opt.ifPresentOrElse(obj -> obj.setAvailable(true), () -> logger.error("…"));
Curry usando vavr o similar puede obtener un código aún más ordenado , pero aún no lo he probado.
fuente
No creo que puedas hacerlo con una sola declaración. Mejor hazlo:
if (!obj.isPresent()) { logger.fatal(...); } else { obj.get().setAvailable(true); } return obj;
fuente
null
cheques? Desde mi punto de vista es peor sin unorElse...
.Optional
por accidente, siempre es una decisión explícita (y peligrosa).Para Java 8 Spring ofrece
ifPresentOrElse
desde "métodos de utilidad para trabajar con opcionales" para lograr lo que desea. Ejemplo sería:import static org.springframework.data.util.Optionals.ifPresentOrElse; ifPresentOrElse(dao.find(), obj -> obj.setAvailable(true), () -> logger.fatal("Object not available"));
fuente
Tendrá que dividir esto en varias declaraciones. Aquí hay una forma de hacerlo:
if (!obj.isPresent()) { logger.fatal("Object not available"); } obj.ifPresent(o -> o.setAvailable(true)); return obj;
Otra forma (posiblemente sobre-diseñada) es usar
map
:if (!obj.isPresent()) { logger.fatal("Object not available"); } return obj.map(o -> {o.setAvailable(true); return o;});
Si
obj.setAvailable
regresa convenientementeobj
, entonces puede simplemente el segundo ejemplo para:if (!obj.isPresent()) { logger.fatal("Object not available"); } return obj.map(o -> o.setAvailable(true));
fuente
En primer lugar,
dao.find()
debe devolver unOptional<Obj>
o tendrá que crear uno.p.ej
o puede hacerlo usted mismo como:
éste volverá
Optional<Obj>
si está presente oOptional.empty()
si no está presente.Así que ahora vayamos a la solución
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; }); }
Este es el delineador que estás buscando :)
fuente
Object
, mientras que la pregunta original es para un método que regresaOptional<Object>
. Mi respuesta (anterior) es muy similar pero difiere de esta manera: stackoverflow.com/a/36681079/3854962flatMap
?No es un
.orElseRun
método, pero se llama.orElseGet
.El principal problema con su pseudocódigo es que
.isPresent
no devuelve unOptional<>
. Pero.map
devuelve unOptional<>
que tiene elorElseRun
método.Si realmente desea hacer esto en una declaración, esto es posible:
public Optional<Obj> getObjectFromDB() { return dao.find() .map( obj -> { obj.setAvailable(true); return Optional.of(obj); }) .orElseGet( () -> { logger.fatal("Object not available"); return Optional.empty(); }); }
Pero esto es incluso más torpe que lo que tenías antes.
fuente
Pude idear un par de soluciones de "una línea", por ejemplo:
obj.map(o -> (Runnable) () -> o.setAvailable(true)) .orElse(() -> logger.fatal("Object not available")) .run();
o
obj.map(o -> (Consumer<Object>) c -> o.setAvailable(true)) .orElse(o -> logger.fatal("Object not available")) .accept(null);
o
obj.map(o -> (Supplier<Object>) () -> { o.setAvailable(true); return null; }).orElse(() () -> { logger.fatal("Object not available") return null; }).get();
No se ve muy bien, algo así
orElseRun
sería mucho mejor, pero creo que esa opción con Runnable es aceptable si realmente quieres una solución de una línea.fuente
Para aquellos de ustedes que quieran ejecutar un efecto secundario solo si no hay un opcional
es decir, un equivalente de
ifAbsent()
oifNotPresent()
aquí hay una ligera modificación a las grandes respuestas ya proporcionadas.myOptional.ifPresentOrElse(x -> {}, () -> { // logic goes here })
fuente
Necesita Optional.isPresent () y orElse () . Su fragmento no funcionará porque no devuelve nada si no está presente.
El objetivo de Optional es devolverlo del método.
fuente
Con Java 8
Optional
se puede hacer con:Optional<Obj> obj = dao.find(); obj.map(obj.setAvailable(true)).orElseGet(() -> { logger.fatal("Object not available"); return null; });
fuente
ifPresentOrElse también puede manejar casos de punteros nulos. Enfoque fácil.
Optional.ofNullable(null) .ifPresentOrElse(name -> System.out.println("my name is "+ name), ()->System.out.println("no name or was a null pointer"));
fuente
Supongo que no puede cambiar el
dao.find()
método para devolver una instancia deOptional<Obj>
, por lo que debe crear el apropiado usted mismo.El siguiente código debería ayudarte. He creado la clase
OptionalAction
, que le proporciona el mecanismo if-else.public class OptionalTest { public static Optional<DbObject> getObjectFromDb() { // doa.find() DbObject v = find(); // create appropriate Optional Optional<DbObject> 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(String[] args) { Optional<DbObject> 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 String toString() { return "DbObject [available=" + available + "]"; } } static class OptionalAction { public static <T> IfAction<T> ifPresent(Optional<T> optional) { return new IfAction<>(optional); } private static class IfAction<T> { private final Optional<T> optional; public IfAction(Optional<T> optional) { this.optional = optional; } public ElseAction<T> then(Consumer<? super T> consumer) { if (optional.isPresent()) consumer.accept(optional.get()); return new ElseAction<>(optional); } } private static class ElseAction<T> { private final Optional<T> optional; public ElseAction(Optional<T> optional) { this.optional = optional; } public void elseDo(Consumer<? super T> consumer) { if (!optional.isPresent()) consumer.accept(null); } } } }
fuente
Optional
tiene sentido. Pero respondí correctamente a su pregunta y proporcioné un ejemplo de trabajo.OptionalAction
como una solución para poder portar el código a java8 parece un poco sobreingeniería, si en java7 esto ya es solo una línea.