java8引入optional类,解决空值异常问题

1,064 阅读3分钟

背景

在平时开发的过程中,在使用一个对象的时候,会先进行空的判断,在非空的情况下,才能获取这个对象的属性值,否则会报NPE(NullPointerException),所以为了解决NullPointerException问题,减少代码中的判空,Java8引入了一个新的Optional类。

介绍

  • Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

  • Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

  • Optional 类的引入很好的解决空指针异常。

长什么样呢?如下

public String result(User user) {
        String result = Optional.ofNullable(user)
                .map(User::getSchool)
                .map(School::getClass)
                .map(Class::getName)
                .orElse("null");
        return result;
}

API

1. 创建optional实例

Optional、empty、of、ofNullabe

  • Optional:构造函数,可以看到是private,也就是不能从外部调用。
private static final Optional<?> EMPTY = new Optional<>();
  • empty:返回一个空的optional对象
    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }
  • of:为非null的值创建一个Optional。
    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }
  • ofNullable:如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。
源码: 
public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);

使用
Optional<User> opt = Optional.ofNullable(user);

通过源码可以看出of和ofNullabe的区别:

当value为空时,of会报空指针异常,而ofNullabe会返回一个空optional

2. 获取optional对象的值

get:如果Optional有值则将其返回,否则抛出NoSuchElementException,所以在用之前需要判空

源码:
    public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }

使用:
User user = Optional.get();

注:避免使用Optional.get()。如果你不能证明是否有值,那么永远不要调用get()

3. 判断是否存在

isPresent()和ifPresent(Consumer<? super T> consumer)

  • isPresent():如果值存在则方法会返回true,否则返回 false
源码:
    public boolean isPresent() {
        return value != null;
    }
    
使用:
if (opt.isPresent()) {
  //do something
}
  • ifPresent(Consumer<? super T> consumer):如果值存在则使用该值调用 consumer , 否则不做任何事情。
源码
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }
使用
    optional.ifPresent(s -> {
        //do something
    });

4. 返回默认值

orElse(T other)、orElseGet(Supplier<? extends T> other)和orElseThrow(Supplier<? extends X> exceptionSupplier)

  • orElse:如果有值则将其返回,否则返回指定的其它值
源码
    public T orElse(T other) {
        return value != null ? value : other;
    }
使用
User user=Optional.offNullable(user).orElse(createUser());
  • orElseGet:如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果
源码
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }
    
使用
User user=Optional.offNullable(user).orElseGet(createUser());

咋一看,好像没什么区别,这两者真正的区别在于,orElse不管optional对象是否空,都会触发createUser()方法;而orElseGet只有在空的情况下,才会触发createUser()。

  • orElseThrow:如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常
源码
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }
    
使用
Optional.ofNullable(user).orElseThrow(()->new Exception("用户为空"));

5. 转换值

map(Function<? super T, ? extends U> mapper)和flatMap(Function<? super T, Optional<U>> mapper)

  • map:如果有值,则对其执行调用映射函数得到返回值,否则返回空Optional。
源码
    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));
        }
    }
使用
Optional.ofNullable(user).map(u-> u.getName());
  • flatMap:如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional
Optional.ofNullable(user).map(u-> u.getName());源码
    public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Objects.requireNonNull(mapper.apply(value));
        }
    }
使用
Optional.ofNullable((user).map(u-> Optional.ofNullable(u.getName());

区别:flatMap和map的区别在于接收的参数不同。

6. 过滤值

filter(Predicate<? super predicate)

如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional

源码
    public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
    }
    
使用:name不为空则返回,否则返回空optional
Optional<User> opt = Optional.ofNullable(user).filter(u -> u.getName() != null);

总结

Optional是为了解决空指针异常,但并不能一上来就用,一些简单的代码即可达到目的

使用Optional后,虽然代码优雅了,但是逻辑性没那么明显,可读性也变差了。

所以不可滥用,酌情使用。比如:当你在返回值不确定的时候,可以使用optional作为返回类型。

关注公众号:臻大虾,分享更多java干货