用过Java的童鞋应该有很深的体会,Java中经常会出现NPE(NullPointException,空指针)异常,如果不处理好是一件非常头疼的事情,而为了处理NPE需要增加很多代码来避免,造成代码污染,有洁癖的童鞋可能会受不了哇。在Java8之前,这类人就喜欢用Google公司著名的Guava库的Optional类来处理NPE问题,使我们的Java代码更干净,也许是受到Guava启发,Java8也引入了Optional,连名字都一模一样。
一、引子
我们先来看一段代码:
public String getGender(Cat cat) {
if(null == cat) {
return "未知";
}
if(cat.getGender() == 0) {
return "公的";
}
return "母的";
}
可以看出,为了处理NPE我们写了很多防御性的代码来避免。
二、Optional如何优雅处理NPE
public String getGender(Cat cat) {
return Optional.ofNullable(cat).map(c -> c.getGender() == 0 ? "公的" : "母的").orElse("未知");
}
简洁、优雅有木有。
三、Optional的实现原理
通过查看Optional源码我们可以看出,Optional的狗子函数是私有的,因此不能直接通过new 来创建Optional对象,它有三个静态方法:
public staticOptional of(T value) {
return new Optional<>(value);
}
public staticOptional ofNullable(T value) {
return value == null ? empty() : of(value);
}
public staticOptional empty() {
@SuppressWarnings("unchecked")
Optionalt = (Optional ) EMPTY;
return t;
}
三个方法都好理解,唯一要多一句嘴的就是of和ofNullable的区别,从实现上可以知道,of表明Optional包含的对象是绝对不允许为空的,如果为空就会爆NPE,而ofNullable则表示允许为空,最终是不是空交给用户去处理。一般情况下ofNullable可以满足我们绝大部分使用场景。那洁癖的童鞋该问了,有了ofNullable为啥还要of?按我的理解,我认为of的使用场景在于明确必须不为空的情况下,如果为空一定要爆NPE,例如我们创建对象时可以这么写:
Optional.of(new Cat());
这时,我们就必须保证new Cat()不为空,如果为空说明内存溢出了,必须马上爆出异常通知。
Optional还有几个方法做一下解释:
(1)get
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
当用Optional.get()时,若包含对象为空,将会抛出NoSuchElementException异常。
(2)isPresent
public boolean isPresent() {
return value != null;
}
该方法只是做了次判空操作,我觉得在实际应用中是没有什么价值的,因为它只是把判空操作封装成一个方法,仅此而已
(3)ifPresent
public void ifPresent(Consumer super T> consumer) {
if (value != null)
consumer.accept(value);
}
该方法接受一个函数式接口Consumer,Consumer与Function类似,只是Function有返回处理结果,而Consumer没有。由于ifPresent内部已经做过判空操作,因此我们可以直接使用无需担心NPE问题。
(4)filter
public Optionalfilter(Predicate super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
我们可以通过filter方法对内容进行过滤,例如我们可以过滤出猫龄大于5的猫
public static void filterAge(Cat cat)
{
Optional.ofNullable(cat).filter( c -> c.getAge() > 5).ifPresent(c -> System.out.println("The cat age is more than 5."));
}
(5)map
public Optional map(Function super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
map方法用于映射,即通过某种规则将对象映射为另外一个对象,上面我们写的getGender就用了map方法。
(6)orElse、orElseGet、orElseThrow
// 该方法允许Optional处理当内容为空时的替代值,或默认值
public T orElse(T other) {
return value != null ? value : other;
}
// 该方法允许通过一个Supplier函数接口返回一个其他值
public T orElseGet(Supplier extends T> other) {
return value != null ? value : other.get();
}
// 该方法是当为空时抛出异常
publicT orElseThrow(Supplier extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
掌握了Optional,我们也可以写出简洁优雅的Java代码。
閱讀更多 鷹眼世界 的文章