在Java 8中,我想对一个可选对象做一些事情,如果它是存在的,并做另一件事,如果它不存在。
if (opt.isPresent()) {
System.out.println("found");
} else {
System.out.println("Not found");
}
不过,这不是一种“功能性风格”。
Optional有一个ifPresent()方法,但我无法链orElse()方法。
因此,我不能写:
opt.ifPresent( x -> System.out.println("found " + x))
.orElse( System.out.println("NOT FOUND"));
回复@assylias,我不认为Optional.map()适用于以下情况:
opt.map( o -> {
System.out.println("while opt is present...");
o.setProperty(xxx);
dao.update(o);
return null;
}).orElseGet( () -> {
System.out.println("create new obj");
dao.save(new obj);
return null;
});
在本例中,当出现opt时,我更新它的属性并保存到数据库。当它不可用时,我创建一个新的obj并保存到数据库。
注意,在两个lambda中,我必须返回null。
但是当opt存在时,两个lambdas都将被执行。Obj将被更新,一个新的对象将被保存到数据库中。这是因为在第一个lambda中返回null。orElseGet()将继续执行。
没有一个很好的方法可以打破常规。如果你想在常规的基础上使用更干净的语法,那么你可以创建一个实用工具类来帮助你:
public class OptionalEx {
private boolean isPresent;
private OptionalEx(boolean isPresent) {
this.isPresent = isPresent;
}
public void orElse(Runnable runner) {
if (!isPresent) {
runner.run();
}
}
public static <T> OptionalEx ifPresent(Optional<T> opt, Consumer<? super T> consumer) {
if (opt.isPresent()) {
consumer.accept(opt.get());
return new OptionalEx(true);
}
return new OptionalEx(false);
}
}
然后你可以在其他地方使用静态导入来获得与你想要的语法相近的语法:
import static com.example.OptionalEx.ifPresent;
ifPresent(opt, x -> System.out.println("found " + x))
.orElse(() -> System.out.println("NOT FOUND"));
所描述的行为可以通过使用Vavr(以前称为Javaslang)来实现,Vavr是Java 8+的对象函数库,它实现了大多数Scala构造(Scala是一种表现力更强的语言,在JVM上构建了更丰富的类型系统)。它是一个非常好的库,可以添加到Java项目中来编写纯函数式代码。
Vavr提供了Option单子,它提供了使用Option类型的函数,例如:
折叠:在两种情况下映射选项的值(已定义/空)
onEmpty:当选项为空时允许执行一个可运行对象
Peek:允许使用选项的值(当定义时)。
与可选相反,它也是可序列化的,这意味着你可以安全地使用它作为方法参数和实例成员。
选项遵循单子法则,不同于Java的可选“伪单子”,并提供了更丰富的API。当然,你也可以从Java的Optional(或其他方式)中实现:Option.ofOptional(javaOptional) -Vavr专注于互操作性。
看这个例子:
// AWESOME Vavr functional collections (immutable for the gread good :)
// fully convertible to Java's counterparts.
final Map<String, String> map = Map("key1", "value1", "key2", "value2");
final Option<String> opt = map.get("nonExistentKey"); // you're safe of null refs!
final String result = opt.fold(
() -> "Not found!!!", // Option is None
val -> "Found the value: " + val // Option is Some(val)
);
此外,所有Vavr类型都可以转换为Java对应的类型,例如:Optional javaOptional = opt.toJava(),非常简单:)当然,转换也存在于另一种方式:Option Option = Option. ofoptional (javaOptional)。
注意:Vavr提供了一个io.vavr.API类,其中有很多方便的静态方法=)
进一步的阅读
空引用,十亿美元的错误
注意:这只是Vavr提供的一个非常小的例子(模式匹配,流也就是惰性评估列表,单体类型,不可变集合,…)
问题是:
optional
.map(object -> {
System.out.println("If present.");
return null;
})
.orElseGet( () -> {
System.out.println("If empty.");
return null;
});
map()是否将第一个函数返回的null转换为empty();然后返回empty()。当它返回empty()时,它提示调用第二个函数。注意,orElseGet()不会将第二个函数返回的null转换为empty(),因此它将返回null。
参见map()的实现:
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
和orElseGet()的实现:
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
因此执行时:
if optional.isPresent(),系统将打印if present。,则If为空。,表达式将求值为null。
if !optional.isPresent(),系统将打印if为空。,表达式将求值为null。
如果提供给map()的函数返回任何其他值-任何其他值-代码将如您所期望的那样工作,如果isPresent()则执行提供给map()的函数,如果!isPresent()则执行提供给orElseGet()的函数:
例如,这个:
optional
.map(data -> {
System.out.println("If present.");
return 0;
})
.orElseGet( () -> {
System.out.println("If empty.");
return 0;
});
当执行:
if optional.isPresent(),系统将打印if present。,表达式的值为0。
if !optional.isPresent(),系统将打印if为空。,表达式的值为0。
如果是你的特定情况,我建议你的insert和update方法返回持久化对象,或者持久化对象的id,或者类似有用的东西;然后你可以使用类似这样的代码:
final Object persist = optional
.map(object -> {
System.out.println("If present.");
return update(object);
})
.orElseGet( () -> {
System.out.println("If empty.");
return insert(new Object());
});