我想用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"));
}
在Java 9或更高,ifPresentOrElse
是最有可能你想要什么:
Optional<> opt = dao.find();
opt.ifPresentOrElse(obj -> obj.setAvailable(true),
() -> logger.error("…"));
柯里使用vavr或类似可能会甚至更整洁的代码,但我还没试过。
我不认为你可以在一个声明中做到这一点。做的更好:
if (!obj.isPresent()) {
logger.fatal(...);
} else {
obj.get().setAvailable(true);
}
return obj;
你将不得不把它们分割多个语句。这里是做的一个方法:
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));
首先,你dao.find()
要么返回一个Optional<Obj>
否则你就必须创建一个。
EG
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;
});
}
这就是你要找的人班轮:)
对于Java 8 Spring提供ifPresentOrElse
从“实用方法与选配工作”,实现你想要什么。例子:
import static org.springframework.data.util.Optionals.ifPresentOrElse;
ifPresentOrElse(dao.find(), obj -> obj.setAvailable(true), () -> logger.fatal("Object not available"));
有一个.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();
});
}
但是,这是不是你有什么之前,甚至笨重。
我能想出了一对夫妇的“一条线”的解决方案,例如:
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的这种选择是可以接受的,如果你真的想要一个在线解决方案。
你需要Optional.isPresent()和orElse()。您的片段赢得;吨的工作,因为它不一样,如果不存在任何回报。
可选的点是从方法返回。
我想你不能改变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);
}
}
}
}