Java8特性Optional类源码阅读
Optional类隶属于java.util包中
Optional 类是一个可以为null的容器对象,它的出现很好的解决空指针异常。
简而言之,这个类的出现,相当于Java8提供了一个封装好的容器,在使用的时候可以放心大胆的处理null的逻辑或异常。需要把值放入容器中,后续的取值操作和其他逻辑,使用其提供的Api即可方便简单的处理null指针的情况。
Optional类的源码数量并不多,有时间还是可以看看的,先看看3个初始化容器内容的静态方法,(empty,of,ofNullable),由于所有构造函数都是private的,所以只能使用工厂方法来获取Optional的实例
在类中第一行便是定义了一个静态常量 EMPTY ,泛型的使用的是通配符 ? ,意思是可以传入任意类型,并赋值为空参构造实例,第二行定义为 final 的 value ,则是用于存储放入容器中的值 /** * 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 ,然后返回强转后的值,可以调用该方法返回一个值为null 的Optional 容器 public static Optional empty() { @SuppressWarnings("unchecked") Optional t = (Optional) EMPTY; return t; }
使用方式,声明一个 value 类型为 String 的空容器 Optional empty = Optional.empty();静态方法of
这个方法相当于要求传入一个值,该值会做为容器中的值,调用顺序是传入值后,调用 Optional 的构造方法,而构造方法会调用 Objects.requireNonNull 方法去判断传入的值是否为空,如果为空则直接抛出空指针异常 NullPointerException ,不为空则返回值并赋值给成员属性 value public static Optional of(T value) { return new Optional<>(value); } private Optional(T value) { this.value = Objects.requireNonNull(value); }
构造函数中调用的 Objects 类的 requireNonNull 方法 public static T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; }
使用方式,声明一个容器,并且值为123,通过实例方法 get 可以获取出使用 of 方法初始化的值 Optional a = Optional.of(123); Integer integer = a.get();静态方法ofNullable
这个方法逻辑比较简单,判断传入的值是否为空,为空则调用上面说的 empty 方法,不为空则调用上面说的of 方法 public static Optional 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 传入Consumer 的accept 中执行 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 { /** * Performs this operation on the given argument. * * @param t the input argument */ void accept(T t); }
使用:分别采取了 匿名内部类 和 lambda表达式 的方式编写,由于 value 不为 null ,所以都会执行accept方法并输出 test 字符串 Optional data = Optional.of("test"); data.ifPresent(new Consumer() { @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 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 { /** * Gets a result. * * @return a result */ T get(); }
使用:分别采取了 匿名内部类 和 lambda表达式 的方式编写,由于 value 的值为 null ,所以最终返回值都是 Supplier实例 的 get方法 返回值 Optional empty = Optional.empty(); String anonymity = empty.orElseGet(new Supplier() { @Override public String get() { return "anonymity"; } }); String lambda = empty.orElseGet(() -> "lambda"); System.out.println(anonymity); System.out.println(lambda); // 输出两行字符串,"anonymity"和"lambda"orElseThrow方法
和orElseGet类似,泛型函数的泛型 作用为返回值类型只能是Throwable 类型或Throwable 的子类型,如果值为空,则直接抛出一个异常 public 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