如果不存在,如何在 Optional 上执行逻辑?
How to execute logic on Optional if not present?
我想用 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"));
}
我不认为你可以在一个声明中做到这一点。最好这样做:
if (!obj.isPresent()) {
logger.fatal(...);
} else {
obj.get().setAvailable(true);
}
return obj;
您需要 Optional.isPresent() and orElse()。您的代码段不会起作用,因为如果不存在,它 return 什么也不会。
Optional 的意义在于 return 它来自于方法。
您必须将其拆分为多个语句。这是一种方法:
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
方便returnsobj
,那么可以简单的把第二个例子改成:
if (!obj.isPresent()) {
logger.fatal("Object not available");
}
return obj.map(o -> o.setAvailable(true));
我想您不能将 dao.find()
方法更改为 return Optional<Obj>
的实例,因此您必须自己创建合适的方法。
以下代码应该可以帮到您。我创建了 class 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);
}
}
}
}
我想出了几个 "one line" 解决方案,例如:
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的选项是可以接受的。
有是一个.orElseRun
方法,但是它叫做.orElseGet
。
您的伪代码的主要问题是 .isPresent
不是 return 和 Optional<>
。但是 .map
return 是一个具有 orElseGet
方法的 Optional<>
。
如果你真的想在一条语句中做到这一点,这是可能的:
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();
});
}
但这比你以前的还要笨重。
首先,您的 dao.find()
应该 return 一个 Optional<Obj>
或者您必须创建一个。
例如
Optional<Obj> = dao.find();
或者您也可以像这样自己做:
Optional<Obj> = Optional.ofNullable(dao.find());
这个将 return 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 9 或更高,ifPresentOrElse
很可能是您想要的:
Optional<> opt = dao.find();
opt.ifPresentOrElse(obj -> obj.setAvailable(true),
() -> logger.error("…"));
使用 vavr 或类似方法进行柯里化可能会得到更整洁的代码,但我还没有尝试过。
对于 Java 8 Spring 从 "Utility methods to work with Optionals" 提供 ifPresentOrElse
来实现你想要的。
例如:
import static org.springframework.data.util.Optionals.ifPresentOrElse;
ifPresentOrElse(dao.find(), obj -> obj.setAvailable(true), () -> logger.fatal("Object not available"));
用 Java 8 Optional
可以用:
Optional<Obj> obj = dao.find();
obj.map(obj.setAvailable(true)).orElseGet(() -> {
logger.fatal("Object not available");
return null;
});
对于那些想要执行副作用的人只有当可选的不存在时
即ifAbsent()
或 ifNotPresent()
的等价物是对已经提供的重要答案的轻微修改。
myOptional.ifPresentOrElse(x -> {}, () -> {
// logic goes here
})
ifPresentOrElse 也可以处理空指针的情况。简单的方法。
Optional.ofNullable(null)
.ifPresentOrElse(name -> System.out.println("my name is "+ name),
()->System.out.println("no name or was a null pointer"));
标题:“如果 Optional 不存在,如何执行逻辑?”
答案:
使用 orElseGet()
作为缺少 ifNotPresent()
的解决方法。因为它希望我们 return 只是 return
null
.
Optional.empty().orElseGet(() -> {
System.out.println("The object is not present");
return null;
});
//output: The object is not present
或
Optional.ofNullable(null).orElseGet(() -> {
System.out.println("The object is not present");
return null;
});
//output: The object is not present
我也用它来轻松实现 singleton pattern 延迟初始化。
public class Settings {
private Settings(){}
private static Settings instance;
public static synchronized Settings getInstance(){
Optional.ofNullable(instance).orElseGet(() -> instance = new Settings());
return instance;
}
}
当然getInstance()
的内容可以直接return第一条写成一行,但是我想演示一下orElseGet()
作为[=14]的用法=].
我想用 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"));
}
我不认为你可以在一个声明中做到这一点。最好这样做:
if (!obj.isPresent()) {
logger.fatal(...);
} else {
obj.get().setAvailable(true);
}
return obj;
您需要 Optional.isPresent() and orElse()。您的代码段不会起作用,因为如果不存在,它 return 什么也不会。
Optional 的意义在于 return 它来自于方法。
您必须将其拆分为多个语句。这是一种方法:
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
方便returnsobj
,那么可以简单的把第二个例子改成:
if (!obj.isPresent()) {
logger.fatal("Object not available");
}
return obj.map(o -> o.setAvailable(true));
我想您不能将 dao.find()
方法更改为 return Optional<Obj>
的实例,因此您必须自己创建合适的方法。
以下代码应该可以帮到您。我创建了 class 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);
}
}
}
}
我想出了几个 "one line" 解决方案,例如:
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的选项是可以接受的。
有是一个.orElseRun
方法,但是它叫做.orElseGet
。
您的伪代码的主要问题是 .isPresent
不是 return 和 Optional<>
。但是 .map
return 是一个具有 orElseGet
方法的 Optional<>
。
如果你真的想在一条语句中做到这一点,这是可能的:
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();
});
}
但这比你以前的还要笨重。
首先,您的 dao.find()
应该 return 一个 Optional<Obj>
或者您必须创建一个。
例如
Optional<Obj> = dao.find();
或者您也可以像这样自己做:
Optional<Obj> = Optional.ofNullable(dao.find());
这个将 return 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 9 或更高,ifPresentOrElse
很可能是您想要的:
Optional<> opt = dao.find();
opt.ifPresentOrElse(obj -> obj.setAvailable(true),
() -> logger.error("…"));
使用 vavr 或类似方法进行柯里化可能会得到更整洁的代码,但我还没有尝试过。
对于 Java 8 Spring 从 "Utility methods to work with Optionals" 提供 ifPresentOrElse
来实现你想要的。
例如:
import static org.springframework.data.util.Optionals.ifPresentOrElse;
ifPresentOrElse(dao.find(), obj -> obj.setAvailable(true), () -> logger.fatal("Object not available"));
用 Java 8 Optional
可以用:
Optional<Obj> obj = dao.find();
obj.map(obj.setAvailable(true)).orElseGet(() -> {
logger.fatal("Object not available");
return null;
});
对于那些想要执行副作用的人只有当可选的不存在时
即ifAbsent()
或 ifNotPresent()
的等价物是对已经提供的重要答案的轻微修改。
myOptional.ifPresentOrElse(x -> {}, () -> {
// logic goes here
})
ifPresentOrElse 也可以处理空指针的情况。简单的方法。
Optional.ofNullable(null)
.ifPresentOrElse(name -> System.out.println("my name is "+ name),
()->System.out.println("no name or was a null pointer"));
标题:“如果 Optional 不存在,如何执行逻辑?”
答案:
使用 orElseGet()
作为缺少 ifNotPresent()
的解决方法。因为它希望我们 return 只是 return
null
.
Optional.empty().orElseGet(() -> {
System.out.println("The object is not present");
return null;
});
//output: The object is not present
或
Optional.ofNullable(null).orElseGet(() -> {
System.out.println("The object is not present");
return null;
});
//output: The object is not present
我也用它来轻松实现 singleton pattern 延迟初始化。
public class Settings {
private Settings(){}
private static Settings instance;
public static synchronized Settings getInstance(){
Optional.ofNullable(instance).orElseGet(() -> instance = new Settings());
return instance;
}
}
当然getInstance()
的内容可以直接return第一条写成一行,但是我想演示一下orElseGet()
作为[=14]的用法=].