Как выполнить логику по опции, если нет?
Я хочу заменить следующий код с помощью java8 Optional
:
public Obj getObjectFromDB() {
Obj obj = dao.find();
if (obj != null) {
obj.setAvailable(true);
} else {
logger.fatal("Object not available");
}
return obj;
}
Следующий псевдокод не работает, поскольку нет метода orElseRun
, но в любом случае он иллюстрирует мою цель:
public Optional<Obj> getObjectFromDB() {
Optional<Obj> obj = dao.find();
return obj.ifPresent(obj.setAvailable(true)).orElseRun(logger.fatal("Object not available"));
}
Ответы
Ответ 1
С Java 9 или выше, ifPresentOrElse
, скорее всего, то, что вы хотите:
Optional<> opt = dao.find();
opt.ifPresentOrElse(obj -> obj.setAvailable(true),
() -> logger.error("…"));
При каррировании с использованием vavr или тому подобного может получиться более аккуратный код, но я еще не пробовал.
Ответ 2
Я не думаю, что вы можете сделать это в одном заявлении. Лучше сделайте:
if (!obj.isPresent()) {
logger.fatal(...);
} else {
obj.get().setAvailable(true);
}
return obj;
Ответ 3
Вам придется разделить это на несколько утверждений. Вот один из способов сделать это:
if (!obj.isPresent()) {
logger.fatal("Object not available");
}
obj.ifPresent(o -> o.setAvailable(true));
return obj;
Другой способ (возможно, чрезмерно спроектированный) - использовать map
:
if (!obj.isPresent()) {
logger.fatal("Object not available");
}
return obj.map(o -> {o.setAvailable(true); return o;});
Если obj.setAvailable
удобно возвращает obj
, то вы можете просто второй пример:
if (!obj.isPresent()) {
logger.fatal("Object not available");
}
return obj.map(o -> o.setAvailable(true));
Ответ 4
Прежде всего, ваш dao.find()
должен либо вернуть Optional<Obj>
, либо создать его.
например.
Optional<Obj> = dao.find();
или вы можете сделать это самостоятельно:
Optional<Obj> = Optional.ofNullable(dao.find());
этот возвращает Optional<Obj>
, если присутствует, или Optional.empty()
, если не присутствует.
Итак, теперь перейдем к решению,
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;
});
}
Это тот лайнер, который вы ищете:)
Ответ 5
Там есть метод .orElseRun
, но он называется .orElseGet
, проблема в том, что, в отличие от .map
, .isPresent
не возвращает Optional<Obj>
.
Если вы действительно хотите сделать это в одном утверждении, это возможно:
public Obj getObjectFromDB() {
return dao.find()
.map( obj -> {
obj.setAvailable(true);
return Optional.of(obj);
})
.orElseGet( () -> {
logger.fatal("Object not available");
return Optional.empty();
});
}
Но это даже clunkier чем то, что у вас было до этого.
Ответ 6
Для Java 8 Spring предлагает ifPresentOrElse
из "Утилиты для работы с ifPresentOrElse
" для достижения того, что вы хотите. Примером будет:
import static org.springframework.data.util.Optionals.ifPresentOrElse;
ifPresentOrElse(dao.find(), obj -> obj.setAvailable(true), () -> logger.fatal("Object not available"));
Ответ 7
Вам нужно Optional.isPresent() и orElse(). Ваш фрагмент выиграл, потому что он ничего не возвращает, если не присутствует.
Точкой необязательного является возврат ее из метода.
Ответ 8
Я смог придумать пару решений "одной строки", например:
obj.map(o -> (Runnable) () -> o.setAvailable(true))
.orElse(() -> logger.fatal("Object not available"))
.run();
или
obj.map(o -> (Consumer<Object>) c -> o.setAvailable(true))
.orElse(o -> logger.fatal("Object not available"))
.accept(null);
или
obj.map(o -> (Supplier<Object>) () -> {
o.setAvailable(true);
return null;
}).orElse(() () -> {
logger.fatal("Object not available")
return null;
}).get();
Это выглядит не очень хорошо, что-то вроде orElseRun
будет намного лучше, но я думаю, что опция с Runnable приемлема, если вы действительно хотите однострочное решение.
Ответ 9
Я полагаю, вы не можете изменить метод dao.find()
, чтобы вернуть экземпляр Optional<Obj>
, поэтому вы должны сами создать его.
Следующий код должен помочь вам. Я создал класс OptionalAction
,
который предоставляет вам механизм 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);
}
}
}
}