Java8 新特性连载——Optional用法详解

用过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 static  Optional of(T value) {
return new Optional<>(value);
}

public static
Optional ofNullable(T value) {
return value == null ? empty() : of(value);
}

public static Optional empty() {
@SuppressWarnings("unchecked")
Optional t = (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 Optional filter(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();
}
// 该方法是当为空时抛出异常
public T orElseThrow(Supplier extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}

掌握了Optional,我们也可以写出简洁优雅的Java代码。


分享到:


相關文章: