前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java-Optional类源码分析

Java-Optional类源码分析

作者头像
Fisherman渔夫
发布2020-02-18 16:28:06
5550
发布2020-02-18 16:28:06
举报
文章被收录于专栏:渔夫渔夫

1.引出

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

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

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

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

代码语言:javascript
复制
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)

代码语言:javascript
复制
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类的真正威力所在:

代码语言:javascript
复制
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为空的情况下也不会抛出异常,且在不为空情况下返回一个员工链表的实例对象。

代码语言:javascript
复制
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;
    }


}

控制台输出:

代码语言:javascript
复制
返回一个空的链表
[]

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

  1. map方法是一个映射方法,如果optionalCompany ≠ null,那么调用此lambda方法theCompany->theCompany.getList(),返回含一个value==List<Employee>的Optional对象,否则返回Optional类的静态对象EMPTY
  2. orElseGet方法则是判断调用起的Optional对象若为Optional类的静态对象EMPTY,则执行其lambda表达式,否则(返回一个空链表,并在控制台打印出此操作),直接返回Optional对象的value域。
代码语言:javascript
复制
        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…)。空间和时间上并不大的牺牲,解决了空指针异常问题,不失为一个好的代码编写风格。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.引出
  • 1.1空指针异常所需的常见操作
  • 2.Optional类的源码分析(JDK1.8)
  • 3.Optional类的真正作用:
  • 4.Optional类案例说明:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档