Java-Optional类源码分析

  • 2020 年 2 月 18 日
  • 筆記

1.引出

我们在对象调用对象的方法、域的时候总是要进行判断对象是否为空的操作,即空指针异常(NullPointerException)。 本质上,这是一个包含有可选值的包装类,这意味着 Optional类既可以含有对象也可以为空。 Optional是Java8提出的新特性,就是为解决空指针异常,方便函数式编程的新特性。

1.1空指针异常所需的常见操作

我们从一个简单的用例开始。在 Java 8 之前,任何访问对象方法或属性的调用都可能导致 NullPointerException

String isocode = user.getAddress().getCountry().getIsocode().toUpperCase(); 在这个小示例中,如果我们需要确保不触发异常,就得在访问每一个值之前对其进行明确地检查:

if (user != null) {      Address address = user.getAddress();      if (address != null) {          Country country = address.getCountry();          if (country != null) {              String isocode = country.getIsocode();              if (isocode != null) {                  isocode = isocode.toUpperCase();              }          }      }  }

你看到了,这很容易就变得冗长,难以维护。


2.Optional类的源码分析(JDK1.8)

package java.util;  //1.以下4个接口的import用于lambda表达式传入的函数式编程,一个接口用于之后介绍的单独一个方法的执行    import java.util.function.Consumer;  import java.util.function.Function;  import java.util.function.Predicate;  import java.util.function.Supplier;      public final class Optional<T> {    	//2.调用了4中的构造器,用于创建一个私有的value域指向null的Optional对象EMPTY(每个类只有一个且不能更改)  	//EMPTY之所以大写是因为其作为一个引用变量是不可变的。        private static final Optional<?> EMPTY = new Optional<>();      //3.用于存储传入的泛型对象或基本类型,如果空,则其值为null        private final T value;        //4.其为无参构造器:用于创建一个value=null的Optional的对象,而Optional对象不等于null,且返回的不是EMPTY域,而是再创建一个结构相同的对象返回        private Optional() {          this.value = null;      }      	//5.返回一个空的Optional对象,即EMPTY,其泛型类型会被转为调用时具体类型,尽管value指向null        public static<T> Optional<T> empty() {          @SuppressWarnings("unchecked")          Optional<T> t = (Optional<T>) EMPTY;          return t;      }    	//6.其为带参数的构造器,返回一个指定非null值的Optional。requireNonNull方法是Objects类的泛型静态方法(不是Object类的方法,要注意),其用途就是构造器的输入参数value为空,则抛出空指针异常,否则,直接返回value.    	/*	相当于以下语句所达到的效果,但由于其可能会被反复调用,:  	*	if (value == null)  	*	throw new NullPointerException();  	*	return obj;  	*  	**/        private Optional(T value) {          this.value = Objects.requireNonNull(value);      }        //7.of静态方法是Optional的静态工厂方法,这用于返回Optional的实例,但其输入value必须不为null,否则抛出空指针异常。      //而Optional的构造器都是私有的,无法使用new关键字构造其对象。        public static <T> Optional<T> of(T value) {          return new Optional<>(value);      }  	//8.ofNUllable字面意思上就能理解就是允许输入参数为null(Nullable)的of方法。当value==null时,调用empty()方法,  	//构造一个value值为null的Optional对象返回;否则,构造一个非空value值的optional对象返回。        public static <T> Optional<T> ofNullable(T value) {          return value == null ? empty() : of(value);      }      	//9.get方法作为一个非静态方法,通常是被使用of/ofNullable静态方法的Optional对象所调用,返回其所存域:value。例如下面代码:    	//Optional中的大多非静态方法,都是由以下结构调用的;      	/**  object:创建的非空对象,method则是属于object类的方法  	*	Optional.ofNullable(object).get().method();  	**/        public T get() {          if (value == null) {              throw new NoSuchElementException("No value present");          }          return value;      }    	//10.返回boolean值,用于value值是否为空的判断结果给出,注意,这不是判断Optional对象是否为空        public boolean isPresent() {          return value != null;      }    	//11.如果value≠null,则使用该值作为参数调用实现Consumer接口的lambda表达式;否则,不做任何事情。  	//Consumer是一个有单个泛型输入参数、无返回值的一个由JDK提供的接口        public void ifPresent(Consumer<? super T> consumer) {          if (value != null)              consumer.accept(value);      }    	//12.其为一个非静态方法,需要Option类的工厂方法返回对象来调用  	//首先,输入接口类型参数(一般为lambda表达式)必须非空,否则爆空指针错误;  	//其次,判断optional对象的value值是否为空,是则直接返回optional对象;  	//第三步,判断存入的value是否匹配给定的 predicate;  	//是,则返回返回optional对象,否则返回新建的value为空的optional对象。    	//综上,空指针异常出现在:lambda表达式为空,只有value非空且符合predicate才返回此optional对象,否则从结果上来看都是返回  	//value==null的optional对象。      public Optional<T> filter(Predicate<? super T> predicate) {          Objects.requireNonNull(predicate);          if (!isPresent())              return this;          else              return predicate.test(value) ? this : empty();      }    	//Lambda为null则抛出空指针异常。如果value==null,则返回一个value==null的Optional对象;否则,  	//对其执行调用映射函数( mapper.apply(value) )得到返回值。如果返回值不为 null,  	//则创建包含映射返回值的Optional作为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));          }      }        //14.如果value ≠ null,则返回基于Optional包含的映射方法的值(mapper.apply(value)),否则(value==null)返回一个空的Optional      //当Lambda表达式为空时,以及当映射返回值为null时,抛出空指针异常。        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));          }      }       //15.如果value ≠ null,则返回value, 否则返回other。        public T orElse(T other) {          return value != null ? value : other;      }       //16.如果value ≠ null,则返回value, 否则调用实现Supplier接口的对象,调用get方法,返回方法返回值(不一定是value)。        public T orElseGet(Supplier<? extends T> other) {          return value != null ? value : other.get();      }    	//17.如果value ≠ null,则返回value,否则抛出由 Supplier 继承的异常        public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {          if (value != null) {              return value;          } else {              throw exceptionSupplier.get();          }      }    	//18.就是简单地对Object类的equals方法的重写,注意,Optional对象即使value值相同,也不会返回true,而是认为是不同的对象。  	//不同于String中的equals方法。    	@Override      public boolean equals(Object obj) {          if (this == obj) {              return true;          }            if (!(obj instanceof Optional)) {              return false;          }            Optional<?> other = (Optional<?>) obj;          return Objects.equals(value, other.value);      }    	//19.调用Objects类的静态方法hasCode,返回存在value的哈希码,如果value==null,则返回 0。      @Override      public int hashCode() {          return Objects.hashCode(value);      }    	//20.返回一个Optional的value.tpString()方法的非空字符串,否则返回约定字符串:"Optional.empty"      @Override      public String toString() {          return value != null              ? String.format("Optional[%s]", value)              : "Optional.empty";      }  }

3.Optional类的真正作用:

Java8中推出了Optional类以及Lambda表达式,这使我们可以方便地进行代码的编写。将这两者结合,才是最常见的使用方式,也是Optional类的真正威力所在:

public class Test {      public static void main(String[] args) {          User user = new User();            Optional.of(user).ifPresent(user1 -> user1.setAge(18));          Optional.of(user).ifPresent(System.out::println);              //而不是设计为如下:          if (Optional.ofNullable(user).isPresent()) {              user.setAge(18);          }            if (Optional.ofNullable(user).isPresent()) {              System.out.println(user);          }          }  }    class User {          private int age;        public int getAge() {          return age;      }        public void setAge(int age) {          this.age = age;      }        @Override      public String toString() {          return "User{" +                  "age=" + age +                  '}';      }  }

lambda在Optional类中的应用才是学习Optional类应该掌握的方法。省略了if的以lambda输入为参数的链式处理,显得更加简洁和拥有更强的逻辑性和更少的出错可能。

4.Optional类案例说明:

 在我们阅读了Optional类的源代码之后,一定可以对其有个初步的认识,现在我们接着阅读关于Optional类使用的一个例子: Company类中有关于员工对象的链表,如以下代码所示:  需求:在company为空的情况下也不会抛出异常,且在不为空情况下返回一个员工链表的实例对象。

public class OptionalTest2 {        public static void main(String[] args) {      	/**   		* 定义员工对象,公司对象初始化。   		*/          Employee employee1 = new Employee("Fisherman");          Employee employee2 = null;          List<Employee> listOfEmployee = Arrays.asList(employee1,employee2);          Company company = new Company(null, listOfEmployee);          company =null;    		/**   		* Optional类的应用   		*/            Optional<Company> optionalCompany = Optional.ofNullable(company);          System.out.println(optionalCompany.map(theCompany->theCompany.getList()).orElseGet(()->{              System.out.println("返回一个空的链表");              return Collections.emptyList();          }));          }      }    /**   * 员工和公司两个类的定义   */    class Employee {      final String name;        public Employee(String name) {          this.name = name;      }  }    class Company {      final String name;        List<Employee> list = new ArrayList<>();        public Company(String name, List<Employee> list) {          this.name = name;r          this.list = list;      }        public List<Employee> getList() {          return list;      }      }

控制台输出:

返回一个空的链表  []

分析:  下面代码是上述功能实现的关键:

  1. map方法是一个映射方法,如果optionalCompany ≠ null,那么调用此lambda方法theCompany->theCompany.getList(),返回含一个value==List<Employee>的Optional对象,否则返回Optional类的静态对象EMPTY
  2. orElseGet方法则是判断调用起的Optional对象若为Optional类的静态对象EMPTY,则执行其lambda表达式,否则(返回一个空链表,并在控制台打印出此操作),直接返回Optional对象的value域。
        Optional<Company> optionalCompany = Optional.ofNullable(company);          System.out.println(optionalCompany.map(theCompany->theCompany.getList()).orElseGet(()->{                System.out.println("返回一个空的链表");              return Collections.emptyList();          }));

 我们之所以不建议返回指向null的list,这是因为由此可能会产生空指针异常,并且长度为0的空list,相关操作一般进入执行语句就相当于执行完毕推出了(长度为0,直接会退出循环、if…)。空间和时间上并不大的牺牲,解决了空指针异常问题,不失为一个好的代码编写风格。