Optional特性
一、Optional的介绍
在实际开发中,最让人头疼的就是NullPointerException
,为了解决这个问题,我们常常需要使用if
语句进行判断,进行防御性的检查,非常繁琐,对于组合了很多甚至多层组合的对象,每一层的拆解都需要判断,这是很可怕的。
在JDK1.8中,引入了Optional
类,可以帮助我们省掉繁琐的非空判断。
二、Optional的常用方法
方法 | 描述 |
---|---|
of | 把指定的值封装为Optional对象,如果指定的值为null,则抛出NullPointerException |
empty | 创建一个空的Optional对象 |
ofNullable | 把指定的值封装为Optional对象,如果指定的值为null,则创建一个空的Optional对象 |
get | 如果创建的Optional中有值存在,则返回此值,否则抛出NoSuchElementException |
orElse | 如果创建的Optional中有值存在,则返回此值,否则返回一个默认值 |
orElseGet | 如果创建的Optional中有值存在,则返回此值,否则返回一个由Supplier接口生成的值 |
orElseThrow | 如果创建的Optional中有值存在,则返回此值,否则抛出一个由指定的Supplier接口生成的异常 |
filter | 如果创建的Optional中的值满足filter中的条件,则返回包含该值的Optional对象,否则返回一个空的Optional对象 |
map | 如果创建的Optional中的值存在,对该值执行提供的Function函数调用 |
flagMap | 如果创建的Optional中的值存在,就对该值执行提供的Function函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象 |
isPresent | 如果创建的Optional中的值存在,返回true,否则返回false |
ifPresent | 如果创建的Optional中的值存在,则执行该方法的调用,否则什么也不做 |
三、Optional方法示范
3.1 empty\of\ofNullable
这三个方法是创建Optional
类的起始方法,其他都是Optional
方法的调用。
@Test
public void testOptional() {
Goods goods = null;
Optional.of(goods); //抛出异常
Optional.ofNullable(goods); //不跑出异常
}
如果即使为空也希望通过Optional进行后续操作,比如orElse,建议使用ofNullable创建
3.2 get
这个方法会检查Optional
中是否有值存在,而不是检查Optional
是否为null,.ofNullable
方法会创建一个空的Optional
对象,而不是一个我们传入的对象,所以如果我们传入的对象是空的,get
方法同样报异常
3.3 Map和orElse的联合妙用
这两个方法的妙用就可以解决我们所谓的多层组合对象层层判空的问题。
我们模拟一个场景:学校类School
,里面包含有一个教师组类TeacherGroup
,教师组类里包含的是我们想得到的教师集合TeacherList
List<Teacher> teachers = Lists.newArrayList(
new Teacher("法外狂徒张三"),
new Teacher("耗子尾汁")
);
TeacherGroup teacherGroup = new TeacherGroup(teachers);
School school = new School(teacherGroup);
我们就可以使用Map和orElse
进行多重处理,保证代码的简洁
List<Teacher> teachersList = Optional.ofNullable(school) //判断学校类是否为空,同时创建Optional类进行后续操作
.map(School::getTeacherGroup) //判断教师组是否为空
.map(TeacherGroup::getTeachers) //判断教师集合是否为空
.orElse(Lists.newArrayList()); //以上有一个不满足,新建集合,否则返回获取到的教师集合
//打印
[{"name":"法外狂徒张三"},{"name":"耗子尾汁"}]
//置空
School school = null; //打印结果为 []
TeacherGroup teacherGroup = null; //打印结果为[]
List<Teacher> teachers = null; //打印结果为[]
3.4 isPresent 和 ifPresent
isPresent
是判定,传入的对象是否为空
Teacher teacher = null;
System.out.println(Optional.ofNullable(teacher).isPresent()); //false
Teacher teacher = new Teacher(); //true
ifPresent
里面是Consumer
函数式接口,也就是说,如果对象为空,不做操作,否则对对象进行操作处理。
Teacher teacher = new Teacher();
Optional.ofNullable(teacher).ifPresent(e -> e.setName("耗子尾汁"));
System.out.println(JackSonUtil.objToJson(teacher)); //打印 {"name":"耗子尾汁"}
Teacher teacher = null; //打印 null
3.5 FlatMap展开
这个类似于Stream
的展开操作,这里不详细讲述,参考Stream API的使用
3.6 orElseGet和orElseThrow
orElseGet
不同于orElse
,这个是要调用一个兜底的方法
@Test
public void testOrElseGet() {
List<Teacher> teachers = null;
List<Teacher> teachers1 = Optional.ofNullable(teachers)
//supplier函数式接口,需要传入某个类的方法,本类调用必须使用this::
.orElseGet(this::getDefaultTeachers);
System.out.println(JackSonUtil.objToJson(teachers1));
}
orElseThrow
抛出异常
@Test
public void testOrElseGet() throws Exception {
List<Teacher> teachers = null;
List<Teacher> teachers1 = Optional.ofNullable(teachers)
.orElseThrow(Exception::new);
}
3.7 Filter
Filter
建议和orElse/orElseGet/orElseThrow
联用
@Test
public void testOptionalFilter() {
Teacher teacher = new Teacher("法外狂徒");
Teacher teacher1 = Optional.ofNullable(teacher)
.filter(t -> !t.getName().equals("法外狂徒"))
.orElse(new Teacher("耗子尾汁"));
System.out.println(JackSonUtil.objToJson(teacher1)); //{"name":"耗子尾汁"}
}