Chcę zamienić następujący kod za pomocą java8 Optional
:
public Obj getObjectFromDB() {
Obj obj = dao.find();
if (obj != null) {
obj.setAvailable(true);
} else {
logger.fatal("Object not available");
}
return obj;
}
Poniższy pseudokod nie działa, ponieważ nie ma orElseRun
metody, ale tak czy inaczej ilustruje mój cel:
public Optional<Obj> getObjectFromDB() {
Optional<Obj> obj = dao.find();
return obj.ifPresent(obj.setAvailable(true)).orElseRun(logger.fatal("Object not available"));
}
Optional
zawsze zwracać wartość wskazaną przez parametr return metody.Odpowiedzi:
W przypadku wersji Java 9 lub nowszej
ifPresentOrElse
najprawdopodobniej chcesz:Optional<> opt = dao.find(); opt.ifPresentOrElse(obj -> obj.setAvailable(true), () -> logger.error("…"));
Curry przy użyciu vavr lub podobnego kodu może dać jeszcze ładniejszy kod, ale jeszcze nie próbowałem.
źródło
Myślę, że nie da się tego zrobić w jednym oświadczeniu. Lepiej zrób:
if (!obj.isPresent()) { logger.fatal(...); } else { obj.get().setAvailable(true); } return obj;
źródło
null
czeków? Z mojego punktu widzenia jest gorzej bez plikuorElse...
.Optional
przypadkowej decyzji, zawsze jest to wyraźna (i niebezpieczna) decyzja.Dla Java 8 Spring oferuje
ifPresentOrElse
od "Metody narzędziowe do pracy z opcjami", aby osiągnąć to, co chcesz. Przykład:import static org.springframework.data.util.Optionals.ifPresentOrElse; ifPresentOrElse(dao.find(), obj -> obj.setAvailable(true), () -> logger.fatal("Object not available"));
źródło
Będziesz musiał podzielić to na wiele instrukcji. Oto jeden sposób, aby to zrobić:
if (!obj.isPresent()) { logger.fatal("Object not available"); } obj.ifPresent(o -> o.setAvailable(true)); return obj;
Innym sposobem (prawdopodobnie nadmiernie zaprojektowanym) jest użycie
map
:if (!obj.isPresent()) { logger.fatal("Object not available"); } return obj.map(o -> {o.setAvailable(true); return o;});
Jeśli
obj.setAvailable
wygodnie wróciszobj
, możesz po prostu drugi przykład:if (!obj.isPresent()) { logger.fatal("Object not available"); } return obj.map(o -> o.setAvailable(true));
źródło
Przede wszystkim
dao.find()
powinieneś albo zwrócić plik,Optional<Obj>
albo będziesz musiał go utworzyć.na przykład
lub możesz to zrobić samodzielnie:
ten wróci,
Optional<Obj>
jeśli jest obecny lubOptional.empty()
nieobecny.A teraz przejdźmy do rozwiązania,
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; }); }
To jedyna wkładka, której szukasz :)
źródło
Object
, podczas gdy oryginalne pytanie dotyczy metody zwracającejOptional<Object>
. Moja (starsza) odpowiedź jest bardzo podobna, ale różni się w ten sposób: stackoverflow.com/a/36681079/3854962flatMap
?Nie jest
.orElseRun
metoda, ale to się nazywa.orElseGet
.Główny problem z pseudokodem polega na tym,
.isPresent
że nie zwraca plikuOptional<>
. Ale.map
zwraca,Optional<>
który maorElseRun
metodę.Jeśli naprawdę chcesz to zrobić w jednej instrukcji, jest to możliwe:
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(); }); }
Ale to jest jeszcze bardziej chrupiące niż to, co miałeś wcześniej.
źródło
Udało mi się wymyślić kilka rozwiązań „jednej linii”, na przykład:
obj.map(o -> (Runnable) () -> o.setAvailable(true)) .orElse(() -> logger.fatal("Object not available")) .run();
lub
obj.map(o -> (Consumer<Object>) c -> o.setAvailable(true)) .orElse(o -> logger.fatal("Object not available")) .accept(null);
lub
obj.map(o -> (Supplier<Object>) () -> { o.setAvailable(true); return null; }).orElse(() () -> { logger.fatal("Object not available") return null; }).get();
Nie wygląda to zbyt ładnie, coś takiego
orElseRun
byłoby znacznie lepsze, ale myślę, że ta opcja z Runnable jest akceptowalna, jeśli naprawdę chcesz rozwiązanie jednokreskowe.źródło
W Javie 8
Optional
można to zrobić za pomocą:Optional<Obj> obj = dao.find(); obj.map(obj.setAvailable(true)).orElseGet(() -> { logger.fatal("Object not available"); return null; });
źródło
Dla tych z Was, którzy chcą wywołać efekt uboczny tylko wtedy, gdy nie ma opcji
tj. odpowiednik
ifAbsent()
lubifNotPresent()
tutaj jest niewielką modyfikacją świetnych odpowiedzi już udzielonych.myOptional.ifPresentOrElse(x -> {}, () -> { // logic goes here })
źródło
Potrzebujesz Optional.isPresent () i orElse () . Twój fragment wygrał; t działa, ponieważ nie zwraca niczego, jeśli nie jest obecny.
Celem Optional jest zwrócenie go z metody.
źródło
ifPresentOrElse może również obsługiwać przypadki nullpointers. Łatwe podejście.
Optional.ofNullable(null) .ifPresentOrElse(name -> System.out.println("my name is "+ name), ()->System.out.println("no name or was a null pointer"));
źródło
Przypuszczam, że nie możesz zmienić
dao.find()
metody zwracania instancjiOptional<Obj>
, więc musisz samodzielnie utworzyć odpowiednią.Poniższy kod powinien ci pomóc. Utworzyłem klasę
OptionalAction
, która zapewnia mechanizm 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); } } } }
źródło
Optional
ma sens. Ale poprawnie odpowiedziałem na twoje pytanie i podałem działający przykład.OptionalAction
jak obejście możliwości przeniesienia kodu do java8, wydaje się nieco przesadne, jeśli w java7 jest to już tylko kilka linijek.