概述
- 1、JDK8最大的一个亮点就是引入了Optional类来解决NPE(NullPointerException)
- 2、阿里开发手册上也推荐使用Optional类来防止NPE
- 3、综上所述,解决NPE正是Optional类的功能,也是JDK8的一份亮点
Optional预览
- 1、Optional类的声明
- 1)被声明为final,即不可被继承
- 2)使用泛型T,即指定Optional所包含对象的类型
public final class Optional<T>
- 2、Optional类的重要属性
- 1)final类型的value,正是Optional包含对象,其中的T为创建Optional时通过泛型指定的类型
- 2)全局静态常量EMPTY,调用的是Optional类的无参构造,其中代表value置为空
private final T value;
private static final Optional<?> EMPTY = new Optional<>();
- 3、Optional类的构造方法
- 可以看出,Optional的两个构造方法均被声明为private——代表外界不可通过new创建Optional对象,即一般在其内部自身使用
private Optional() {
this.value = null;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
Optional初探——API
Methods | Params | Return | Purpose | Theory | Frequency |
---|---|---|---|---|---|
empty() | 无 | Optional<T> | 将Optional的value置空 | 将全局静态常量EMPTY强转为对应的T类型Optional,之后进行返回 | occasional |
of() | T类型变量 | Optional<T> | 创建一个包含value的Optional对象 | 调用Optional有参构造方法,将传递的变量赋给value | often |
ofNullable() | T类型变量 | Optional<T> | 创建一个包含value的Optional对象 | 先判断value是否为空 value为空,直接调用empty方法返回空Optional对象 value非空,调用of方法返回一个非空包含value的Optional对象 |
always |
get() | 无 | T类型变量 | 获取Optional中的value 注意:一般需要先调用isPresent判断value非空 |
当前value为空,则抛出NoSuchElementException 否则直接返回value |
occasional |
isPresent | 无 | 布尔型变量 | 判断Optional中的value是否非空 | 直接判断value是否非空 | occasional |
ifPresent | Consumer消费型接口 | 无 | 对Optional中的value进行指定action | 当value非空,对value进行指定action | usual |
filter | Predicate断言型接口 | Optional<T> | 对Optional中的value进行指定test | 调用Objects工具类对传入的断言型接口进行非空校验 调用isPresent方法,当value为空,直接返回当前Optional对象 当value非空,对value进行指定test,断言成功返回当前Optional对象,断言失败调用empty方法返回空Optional对象 |
often |
map | Function函数型接口 | Optional<U> | 对Optional中的value进行指定apply | 调用Objects工具类对传入的函数型接口进行非空校验 调用isPresent方法,当value为空,直接调用empty方法返回空Optional对象 当value非空,对value进行指定apply,之后调用ofNullable方法对结果封装为新Optional |
usual |
flatMap | Function函数型接口 | Optional<U> | 对Optional中的value进行指定apply 与map类似,但是它不会对结果进行Optional再封装 |
调用Objects工具类判断传入的函数型接口非空 调用isPresent方法,当value为空,直接调用empty方法返回空Optional对象 当value非空,对value进行指定apply,之后调用Objects工具类对结果进行非空校验 |
usual |
orElse | T类型变量 | T类型变量 | 返回Optional中的value,其中value为空则返回传递的变量 | 判断Optional中value是否为空 value非空则返回value value为空则返回传递的T类型变量 |
usual |
orElseGet | Supplier 供给型接口 |
T类型变量 | 返回Optional中的value,其中value为空则返回Supplier生产的T类型变量 | 判断Optional中value是否非空 value非空则返回value value为空则对通过Supplier的get方法生产一个T类型变量返回 |
usual |
orElseThrow | Supplier 供给型接口 |
T类型变量 | 返回Optional中的value,其中value为空则抛出Supplier生产的异常消息 | 判断Optional中value是否非空 value非空则返回value value为空则对通过Supplier的get方法生产一个异常消息 |
occasional |
Optional深究——Demo
注:此处只研究经常使用的方法,其他的方法也不难理解。
- 一般都通过ofNullable方法来创建Optional,因为这样既可以接收非Null,又可以接收Null
- 一般都通过map方法来代替非空判断之后的getter操作
- 一般都通过orElse方法来获取最后的值,其中一般传入null即可
package com.gezq.optionaldemos;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Optional;
/**
* Desc: 简单测试Optional
*
* @author gezq0714
* @version MyDemo:1.0.0
* @email ge051799qi@163.com
* @date 2021/10/1 - 20:49
* @since MyDemo:1.0.0
*/
public class Demo {
public static void main(String[] args) {
// 假设User是数据库中查询出的一个对象,我们想要获取的是skillName
User user = new User("gezq", "123456", new Skill("sing", Optional.of("you like sing")));
// 一般操作
String skillName1 = null;
// 1、判断user非空
if (user != null) {
// 2、获取skill
final Skill skill = user.getSkill();
// 3、判断skill非空
if (skill != null) {
// 4、获取skillName
skillName1 = skill.getSkillName();
}
}
// 使用Optional————使用map获取普通属性的值
final String skillName2 = Optional.ofNullable(user).map(User::getSkill).map(Skill::getSkillName).orElse(null);
// 使用Optional——使用flatMap获取被Optional包装过的属性的值
final String skillIntroduction = Optional.ofNullable(user).map(User::getSkill).flatMap(Skill::getIntroduction).orElse(null);
System.out.println("一般操作获取skillName:" + skillName1);
System.out.println("使用Optional获取skillName:" + skillName2);
System.out.println("使用Optional获取skillIntroduction:" + skillIntroduction);
/*
输出结果如下所示:
一般操作获取skillName:sing
使用Optional获取skillName:sing
使用Optional获取skillIntroduction:you like sing
*/
}
}
@AllArgsConstructor
@NoArgsConstructor
@Data
class User {
private String username;
private String password;
private Skill skill;
}
@AllArgsConstructor
@NoArgsConstructor
@Data
class Skill {
private String skillName;
private Optional<String> introduction;
}