Optional源码分析和使用

841 阅读3分钟

Optional是一个可能包含非空(non-null)的值,也可能不包含非空的值得容器对象。它是一个基于值的类,这里它区别于引用相等,也就是用==来判断;或者是用hash值来判断。如果用Optional来做引用相等性或者hash值得相等性,则会出现一些不可预料的结果,这是应当避免的。

private static final Optional<?> EMPTY = new Optional<>();

上面定义了一个没有内容的空对象,这个对象是静态的不可变的对象。

private final T value;

上面定义了Optional的值。如果这个值为null,那么就表示没有值存在。

private Optional() {
    this.value = null;
}
private Optional(T value) {
    this.value = Objects.requireNonNull(value);
}

上面是2种构造方法。前一种是让value等于null,而后一种是不允许value等于null。后一种方法会在后面用到。

public static <T> Optional<T> of(T value) {
    return new Optional<>(value);
}

从上面可以得出该类的构造方法都是私有的,而of方法则可以获取到一个本类的实例对象。因为这里调用了前面提到的不允许value值为null的私有化构造方法,所以这个方法的参数也是不能为空的。

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

上面这个方法则比of方法更加优雅,因为它允许传入的值为null。

public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}
public boolean isPresent() {
    return value != null;
}

上面的2个方法都可以用来判断值是否存在。第一个是以是否抛出异常为提示信息,第二种则是返回布尔类型的值来判断。

public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}

上面这个方法比仅仅判断值是否存在还要强大一些,它可以在值补位null的时候,进行一些其他的操作。可以参考我前面讲函数式接口那里来理解这个方法。

下面是一些使用的例子:

Optional<String> str = Optional.of("halo");

上面是为了获得一个Optional实例对象。

Optional[halo]

@Override
public String toString() {
    return value != null
        ? String.format("Optional[%s]", value)
        : "Optional.empty";
}

我们打印一下str的结果如上。中括号里面就是对象的内容。看它的toString方法就一目了然了。

Optional<Object> nullVal = Optional.ofNullable(null);//return Optional.empty

上面的这个例子补充了前面的那个例子。

Optional<String> str = Optional.of("halo");
if (str.isPresent()) {
    System.out.println(str.get());
}

先判断str这个Optional容器对象里面是否有值,若有,则用get方法获取到这个值。用idea的同学可以输入str.isPresent().if再enter快速完成代码。

str.ifPresent((value) ->{
    System.out.println("your name is :" + value);
});

用函数式编程来完成一些额外的功能(这里是打印一句话)。

str.ifPresent(System.out :: println);

上面是一种更优雅的写法,这样减少了非空的判断。

System.out.println(str.orElse("bye"));// return halo

System.out.println(Optioal.empty().orElse("bye"));// return bye


上面是orElse的用法。

System.out.println( str.orElseGet(() ->{
    return "nothing";
}));//return halo
 System.out.println( Optional.empty().orElseGet(() ->{
    return "nothing";
}));// return nothing

上面是orElseGet的用法,它和前面orElse方法的区别是,它是用函数的方式来处理值为null的情况。


另外,Optional还衍生出一些诸如OptionalInt, OptionalDouble的类,

总结一下:

1. Optional主要用来处理返回值,不要用它来作为方法的参数,对于方法参数的非空判断,要直接抛出对应的异常,这样可以避免对它下面的代码的干扰

2. 尽量使用orElse或者orElseGet而不要用get方法

3. 不要把Optional作为一个类的字段来使用,因为Optional是不能序列化的