Java-Optional类源码分析
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;
}
}
控制台输出:
返回一个空的链表
[]
分析:
下面代码是上述功能实现的关键:
- map方法是一个映射方法,如果optionalCompany ≠ null,那么调用此lambda方法
theCompany->theCompany.getList()
,返回含一个value==List<Employee>
的Optional对象,否则返回Optional
类的静态对象EMPTY
; - 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…)。空间和时间上并不大的牺牲,解决了空指针异常问题,不失为一个好的代码编写风格。
推荐阅读
-
一种比较简单的分析类图表Word 折线图制作方法
-
三 分析easyswoole源码(启动服务&TableManager,略提及Cache工具的原理)
-
CodeIgniter辅助之第三方类库third_party用法分析,codeigniter类库_PHP教程
-
从PHP的源码中深入了解stdClass类_PHP教程
-
Mybatis接口Mapper内的方法为啥不能重载?Mapper的源码分析
-
Java之HashMap源码分析(第五篇:访问元素)
-
springboot bean循环依赖实现以及源码分析
-
skynet源码分析之service_logger,skynet_error
-
Vue.js 源码分析(三十) 高级应用 函数式组件 详解
-
ThinkPHP中__initialize()和类的构造函数__construct()用法分析,thinkphp构造函数