JDK8新特性03:Optional类-空指针异常的预防手段
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()
returnstrue
. If no value is present, the object is considered empty andisPresent()
returnsfalse
.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) andifPresent(Consumer
(performs an action if a value is present).
Optional
对象是一个容器对象,存放的可以是空或非空对象.通过调用其实例方法isPresent()
方法判断其中存放对象是否为空:若存放的是非空值则返回true
,否则返回false
.
This is a value-based class; use of identity-sensitive operations (including reference equality (
==
), identity hash code, or synchronization) on instances ofOptional
may have unpredictable results and should be avoided.
这是一个value-based
类,我们只需要考虑其中所储存的值,而不应该将其当成一般的对象来看待.对Optional
对象进行任何id敏感的操作(包括:判断引用相等==
,计算hashcode或同步)都会产生不可预知的结果,应该避免这种操作.
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
中方法得到的返回值存入Optional
对象并返回;否则返回一个保存null
的Optional
对象. -
orElseXXX()
一系列方法:若该Optional
对象中存储的是非空对象,返回被存储的对象;否则根据方法不同执行不同的操作-
orElse(T other)
:若该Optional
对象中存储的是非空对象,返回被存储的对象;否则若返回other
. -
orElseGet(Supplier supplier)
:若该Optional
对象中存储的是非空对象,返回被存储的对象;否则返回从生产者supplier
中取出的对象. -
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()). // 若getEmployee()返回空,则返回空Optional
orElse(Collections.EMPTY_LIST); // 若上述两步中有一步为空,则返回空列表
// 遍历员工列表employees
employees.forEach(employee -> System.out.println(employee));
使用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 usingnull
is likely to cause errors. A variable whose type isOptional
should never itself benull
; it should always point to anOptional
instance.
Optional
的主要用途:当某个方法需要明确表示返回值可能为空时,通过将其封装成为Optional
对象以简化操作并规避空指针异常.Optional
引用本身永远不应该为null
,而应该永远指向一个Optional
对象.
这也就是说,我们永远不应当将Optional
对象声明为方法参数或类的成员.
上一篇: 端口扫描类型
下一篇: java 两list求交集