Java8特性-Optional类源码阅读

697 阅读8分钟

Optional类

隶属于java.util包中

Optional 类是一个可以为null的容器对象,它的出现很好的解决空指针异常。

简而言之,这个类的出现,相当于Java8提供了一个封装好的容器,在使用的时候可以放心大胆的处理null的逻辑或异常。需要把值放入容器中,后续的取值操作和其他逻辑,使用其提供的Api即可方便简单的处理null指针的情况。

Optional类的源码数量并不多,有时间还是可以看看的,先看看3个初始化容器内容的静态方法,(empty,of,ofNullable),由于所有构造函数都是private的,所以只能使用工厂方法来获取Optional的实例

在类中第一行便是定义了一个静态常量EMPTY,泛型的使用的是通配符?,意思是可以传入任意类型,并赋值为空参构造实例,第二行定义为finalvalue,则是用于存储放入容器中的值

    /**
     * Common instance for {@code empty()}.
     */
    private static final Optional<?> EMPTY = new Optional<>();
    
    /**
     * If non-null, the value; if null, indicates no value is present
     */
    private final T value;
    
        
    private Optional() {
        this.value = null;
    }

静态方法empty

这个方法作用很简单,就是将类加载时初始化的EMPTY静态常量强转成传入的泛型T,然后返回强转后的值,可以调用该方法返回一个值为nullOptional容器

    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

使用方式,声明一个value类型为String的空容器

    Optional<String> empty = Optional.empty();

静态方法of

这个方法相当于要求传入一个值,该值会做为容器中的值,调用顺序是传入值后,调用Optional的构造方法,而构造方法会调用Objects.requireNonNull方法去判断传入的值是否为空,如果为空则直接抛出空指针异常NullPointerException,不为空则返回值并赋值给成员属性value

    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }
    
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

构造函数中调用的Objects类的requireNonNull方法

    public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }

使用方式,声明一个容器,并且值为123,通过实例方法get可以获取出使用of方法初始化的值

        Optional<Integer> a = Optional.of(123);
        Integer integer = a.get();

静态方法ofNullable

这个方法逻辑比较简单,判断传入的值是否为空,为空则调用上面说的empty方法,不为空则调用上面说的of方法

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

下面看看一些实例方法是怎么实现的

get方法

of方法中演示过用法了,其作用就是返回当前容器中value的值,如果为value为空则直接抛出NoSuchElementException异常

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

isPresent方法

判断当前容器中value的值是否为空,并返回一个boolean

    public boolean isPresent() {
        return value != null;
    }

使用:先判断值是否为空,如果为空直接调用get方法会报错

if (optional.isPresent()) {
    p = optional.get();
}

ifPresent方法

判断当前容器中value的值是否为空,空则什么都不做,不为空则将value传入Consumeraccept中执行

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

java.util.function.Consumer是JDK提供的函数接口,包含了一个无返回值的带参的方法: void accept(T t),传入一个泛型类型的参数并执行一些操作。 由于这是一个函数式接口,可以使用传统的匿名内部类编写,也可以使用Lambda表达式函数接口Lambda表达式在这里不再赘述

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
}

使用:分别采取了匿名内部类lambda表达式的方式编写,由于value不为null,所以都会执行accept方法并输出test字符串

    Optional<String> data = Optional.of("test");
    
    data.ifPresent(new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.println(s);
        }
    });

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

orElse方法

判断当前容器中value的值是否为空,不为空则返回value,空则返回传入的值

    public T orElse(T other) {
        return value != null ? value : other;
    }

使用:由于容器中的值为空,所以会返回test字符串

    Optional<String> empty = Optional.empty();
    System.out.println(empty.orElse("test"));

orElseGet方法

判断当前容器中value的值是否为空,不为空则返回value,空则调用Supplier实例的get方法,<? extends T>的作用为返回值类型只能是T类型T的子类型

    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

java.util.function.Supplier是JDK提供的函数接口,包含了一个无参的方法: T get(), 用来返回一个泛型参数指定类型的对象

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

使用:分别采取了匿名内部类lambda表达式的方式编写,由于value的值为null,所以最终返回值都是Supplier实例get方法返回值

    Optional<String> empty = Optional.empty();
        
    String anonymity = empty.orElseGet(new Supplier<String>() {
        @Override
        public String get() {
            return "anonymity";
        }
    });
    String lambda = empty.orElseGet(() -> "lambda");
        
    System.out.println(anonymity);
    System.out.println(lambda);
    // 输出两行字符串,"anonymity"和"lambda"

orElseThrow方法

和orElseGet类似,泛型函数的泛型<X extends Throwable>作用为返回值类型只能是Throwable类型或Throwable的子类型,如果值为空,则直接抛出一个异常

    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }

使用:分别采取了匿名内部类lambda表达式的方式编写,由于value的值为null,所以最终返回值都是Supplier实例get方法返回值,可以直接往上抛异常或者try catch捕获处理,这段代码执行后便会抛出任意一个异常

    public static void main(String[] args) throws Exception {
        Optional<Object> empty = Optional.empty();

        // 这段注释掉则抛出后面的lambda表达式返回的异常
        empty.orElseThrow(new Supplier<Exception>() {
            @Override
            public IllegalArgumentException get() {
                return new IllegalArgumentException("value is null,from anonymity");
            }
        });

        // 这段注释掉则抛出匿名内部类返回的异常
        empty.orElseThrow((Supplier<Exception>) () -> new IllegalArgumentException("value is null,from lambda"));
    }

map方法

首先判断参数mapper是否为空,空则抛出空指针异常,再判断当前容器中value的值是否为空,空则调用empty方法,不为空则返回ofNullable方法的返回值,ofNullable的参数为mapper的返回值,mapper类型为Function类型,和上面讲过的Supplier类似,作用就是如果值不为空,可以执行一个函数进行二次逻辑数据处理并返回。这个mapper函数有两个泛型T和UT是定义在Optional类名上的,public后面紧跟的<U>作用是声明这个方法有一个泛型U(声明为泛型方法),Function的泛型参数则限定了第一个参数为T类型T的父类型,第二个参数为U类型U的子类型

    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));
        }
    }

java.util.function.Function是JDK提供的函数接口,方法applay的作用就是传入一个值,返回另一个值

@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
}

使用:分别采取了匿名内部类lambda表达式的方式编写,由于value的值不为空,两个变量接受的Optional实例中的值都为3

    Optional<String> data = Optional.of("test");
    
    Optional<Integer> integer = data.map(new Function<String, Integer>() {
        @Override
        public Integer apply(String s) {
            return s.length() > 3 ? 1 : 0;
        }
    });
    Optional<Integer> integer2 = data.map(s -> s.length() > 3 ? 1 : 0);
    
    System.out.println(integer.get());
    System.out.println(integer2.get());
    // 输出两行字符串3

flatMap方法

首先判断参数mapper是否为空,空则抛出空指针异常,再判断当前容器中value的值是否为空,空则调用empty方法,不为空则调用Objects.requireNonNull函数的返回值,将mapper.apply返回值传入,如果apply方法的返回值为空则会抛出异常,使用的方法与map非常类似,唯一区别是map返回值会被调用ofNullable方法进行容器包装,而flatMap要求直接返回Optional容器

    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));
        }
    }

使用:分别采取了匿名内部类lambda表达式的方式编写,使用匿名内部类编写的applay方法返回了一个值为数字1的容器,可调用get输出,使用lambda表达式编写的因为执行Objects.requireNonNull(null)所以抛出异常

    Optional<String> data = Optional.of("test");
    
    Optional<Integer> integer = data.flatMap(new Function<String, Optional<Integer>>() {
        @Override
        public Optional<Integer> apply(String s) {
            return Optional.of(1);
        }
    });

    System.out.println(integer.get());
    // 输出字符串1
    
    data.flatMap(s -> null);
    // 执行到这里就会抛出异常,因为调用了Objects.requireNonNull(null)

filter方法

首先判断参数predicate是否为空,空则抛出空指针异常,再判断当前容器中value的值是否为空,空则返回当前实例,不为空则返回一个三元表达式,会将当前容器的值传入predicate.test函数中,返回一个boolean值,如果true则返回当前实例,否则调用empty函数返回一个空容器,作用就是过滤筛选值。Predicate也是一个函数接口。

    public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
    }

java.util.function.Predicate是JDK提供的函数接口,方法test的作用就是传入一个值,返回一个boolean

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}

使用:分别采取了匿名内部类lambda表达式的方式编写,由于rightlyvalue值不为空,会输出test,而falsely.get()则会抛出异常

    Optional<String> data = Optional.of("test");
    Optional<String> rightly = data.filter(new Predicate<String>() {
        @Override
        public boolean test(String s) {
            return s.equals("test");
        }
    });
    Optional<String> falsely = data.filter(s -> s.equals(""));
        
    System.out.println(rightly.get());
    System.out.println(falsely.get());
    // 会先输出一次"test"
    // 然后falsely.get时就会抛出异常,因为value为null

至此,Optional类中所有的方法和逻辑都阅读完了,源码清晰简单,阅读一遍明白其中的逻辑,对该工具类的使用会有一定的帮助。:)