JDK8新特性03:Optional类-空指针异常的预防手段

Optional类概述

Optional对象是Java8新引入的类,用来预防Java中臭名昭著的NullPointerException问题.阅读Optional类的文档如下:

A container object which may or may not contain a non-null value. If a value is present, isPresent() returns true. If no value is present, the object is considered empty and isPresent() returns false.

Additional methods that depend on the presence or absence of a contained value are provided, such as orElse(Object) (returns a default value if no value is present) and ifPresent(Consumer(performs an action if a value is present).

Optional对象是一个容器对象,存放的可以是空或非空对象.通过调用其实例方法isPresent()方法判断其中存放对象是否为空:若存放的是非空值则返回true,否则返回false.

Optional的使用

Optioinal对象的创建与基本使用

在文档中将Optional类称为value-based类,value-based的一个特征就是没有公共的构造方法,而是通过工厂方法创建.

Optional对象有三个工厂方法:

  • empty():构造一个包含空对象的Optional对象(注意该Optional对象本身不是null,但是它存放的是null.当然,考察对象是否为null就已经脱离了value-based类的本意).
  • of(T value):构造一个包含value对象的Optional对象,若传入的value为空则报错.
  • ofNullable(T value):根据传入的value是否为空判断返回什么类型的Optional对象:若传入的value为空,则返回包含空对象的Optional对象,否则返回包含value对象的Optional对象.

除此之外,Optional对象还有两个实例方法:

  • isPresent():判断该Optional对象中包含的是否为非空对象.
  • get():取出该Optional对象中包含的对象,若该Optional对象包含的null,则报错NoSuchElementException.

使用Optional的上述方法时,与传统的编程方式并无不同,要遵循先判空后操作的规则.(实际上,取出Optional中对象的更常用方法是orElseXXX())

Optional<String> optional = Optional.of("hello");
if (optional.isPresent()) {
    System.out.println(optional.get());
}

Optional的函数式编程接口

Optional对象中的几个方法提供了对函数式编程的支持:

  • ifPresent(Consumer action):若该Optional对象中存储的是非空对象,则调用消费者action来消费.
  • map(Function mapper):若该Optional对象中存储的是非空对象,则将对被储存对象调用mapper中的apply()方法得到的返回值存入Optional对象并返回;否则返回一个保存nullOptional对象.
  • orElseXXX()一系列方法:若该Optional对象中存储的是非空对象,返回被存储的对象;否则根据方法不同执行不同的操作
    1. orElse(T other):若该Optional对象中存储的是非空对象,返回被存储的对象;否则若返回other.
    2. orElseGet(Supplier supplier):若该Optional对象中存储的是非空对象,返回被存储的对象;否则返回从生产者supplier中取出的对象.
    3. orElseThrow(Supplier exceptionSupplier):若该Optional对象中存储的是非空对象,返回被存储的对象;否则抛出从异常生产者exceptionSupplier中取出的异常.

这些方法的区别:ifPresent()直接消费被储存的对象,map()根据储存的对象创建新的Optional对象,orElse()方法取出被储存的对象.

使用上述方法,可以利用实现对Optional对象的函数式编程.

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

optional.ifPresent(item -> System.out.println(item));	// 不会有任何输出

optional.orElse("hello world");			// 返回"hello world"
optional.orElseGet(() -> "hello world");// 返回"hello world"
optional.orElseThrow();					// 抛出NoSuchElementException异常

使用Optional的正确姿势

下面以一个例子演示如何使用Optional避免空指针异常,假设有如下的类

// 员工类
class Employee {
    // Employee类的各种属性...
}

// 公司类,包含员工列表
class Company {

    // 公司类与员工类是一对多的关系
    private List<Employee> employees;
    
    public List<Employee> getEmployees() { return employees; }

    // Company类的其他属性...
}

在Java8以前,我们要想遍历一个Company类的所有Employee时,需要如下操作:

// 模拟从数据库中取出Company对象
Company company = getCompanyFromDatabase();

// 遍历该Company对象的所有Employee,需要对company和employees都判空再操作
if (company != null) {
    List<Employee> employees = company.getEmployees();
    if (employees != null) {
        employees.forEach(employee -> System.out.println(employee));
    }
}

使用Optional的函数式编程接口,我们可以将判空和操作写在同一行

List<Employee> employees = Optional.ofNullable(company).// 若company为空,则返回空Optional
    map(theCompany -> theCompany.getEmployees()).		// 若getEmployees()返回空,则返回空Optional
    orElse(Collections.EMPTY_LIST);						// 若上述两步中有一步为空,则返回空列表

// 遍历员工列表employees
employees.forEach(employee -> System.out.println(employee));

使用Optional类要注意的问题

避免对Optional对象进行id敏感的操作

Optional类是一个**基于值的(value-based)类,应避免对其进行任何id敏感(identity-sensitive)**的操作.阅读文档内容如下:

This is a value-based class; use of identity-sensitive operations (including reference equality (==), identity hash code, or synchronization) on instances of Optional may have unpredictable results and should be avoided.

Optional类是一个**基于值的(value-based)类,我们只需要考虑其中所储存的值,而不应该将其当成一般的对象来看待.对Optional对象进行任何id敏感(identity-sensitive)**的操作(包括:判断引用相等==,计算hashcode或同步)都会产生不可预知的结果,应该避免这种操作.

Optional类只应当用于声明返回值类型

Optional类只能用于声明返回值类型,不应用于声明方法参数类成员的类型.阅读文档内容如下:

Optional is primarily intended for use as a method return type where there is a clear need to represent “no result,” and where using null is likely to cause errors. A variable whose type is Optional should never itself be null; it should always point to an Optional instance.

Optional的主要用途:当某个方法需要明确表示可能会没有结果(no result),但又不适合将返回值声明为null时,通过将其封装成为Optional对象并返回,以简化操作并规避空指针异常.Optional引用本身永远不应该为null,而应该永远指向一个Optional对象.

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值