1.用处
Optional 类是 Java 8 引入的一个特性。Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException),使用它可以避免代码中出现过多的 if (obj != null) { } 这样范式的代码,支持链式编程。
引入:在项目中,经常会遇见需要取出一个处于很深的结构的实体中的某个值,比如
System.out.println(student.getAddress().getCity().getCityName());
如果想要成功无异常的取出需要的cityName的值,需要在访问每一个值之前对其进行判空,这就需要使用 if…{} 的结构,起码需要判断三次,嵌套三层 if…{} 会使得代码非常冗余。而Optional就可以很明显的简化这个过程,实力代码如下:
//直接放入进行一步步的取值即可,不会抛出异常
String cityName = Optional.ofNullable(student)
.map(s -> s.getAddress())
.map(s -> s.getCity())
.map(s -> s.getCityName())
//如果有节点为空,则会打印该值
.orElse("该值,或者前置节点的值为空");
//如果无节点为空,就打印它真实的值;有节点为空就打印 “该值,或者前置节点的值为空”
System.out.println(cityName);
使用Optional可以简化代码,此外它还提供其他的api方法可供调用;
2.创建使用
Optional实际上是将需要处理的实体转化成一个容器对象,然后再对容器进行处理;而将实体转化为容器对象有三种方法:
- Optional.of(obj):它要求传入的 obj 不能是 null 值的, 否则直接报NullPointerException 异常。
- Optional.ofNullable(obj):它以一种智能的,宽容的方式来构造一个 Optional 实例。来者不拒,传 null 进到就得到 Optional.empty(),非 null 就调用 Optional.of(obj)
- Optional.empty():返回一个空的 Optional 对象
可以根据不同的情况分别使用;
使用原则:
1、避免使用Optional.isPresent()
来检查实例是否存在,因为这种方式和null != obj
没有区别,这样用就没什么意义了。
2、避免使用Optional.get()方式来获取实例对象,因为使用前需要使用Optional.isPresent()来检查实例是否存在,否则会出现NoSuchElementException异常问题。所以使用orElse(),orElseGet(),orElseThrow()获得你的结果。
3、尽量使用orElseGet(),因为这个方法只有在传值为空的时候才会执行括号中的函数,而orElse()不管传值是什么,都会执行
括号中的函数,造成资源浪费。
3.常用函数
① isPresent() 如果值存在返回true,否则返回false
它有两个重载方法,一个无入参,只是判断传入的容器是否有值;一个支持一个消费类型函数入参,如果传入容器有值就执行函数,否则不做任何操作;
// 返回student
Student student = createBody();
//无入参方法:判断对象的值是否存在
boolean present = Optional.ofNullable(student).map(s->s.getName()).isPresent();
System.out.println(present ? "不为空" : "为空");
//消费类型函数入参方法:如果值存在就直接打印,不存在就不执行 ifPresent()
Optional.ofNullable(student)
.map(s->s.getName())
.ifPresent(s-> System.out.println(s));
返回结果
// ① 返回student 为null时
null
为空
// ② 返回student 都有值时
Student(name=张三, age=18, address=null)
不为空
张三
② orElse() 如果有值则将其返回,否则返回指定的其它值
orElse() 与 orElseGet() 返回一致,区别在于 orElse() 不管传值是否为空都会先执行括号内函数,而 orElseGet() 只会在传值为空的情况下执行,因此一般推荐使用 orElseGet() 进行处理。
还有一个orElseThrow() 该方法是有值则将其返回,没有值将返回指定的异常;
代码举例:
Student student = createBody();
//不报错
System.out.println(student);
//不管传值是否为空都会先执行括号内函数
String s1 = Optional.ofNullable(student)
.map(s -> s.getName())
.orElse(returnDeault());
System.out.println(s1);
//传值为空的情况下才执行
String s2 = Optional.ofNullable(student)
.map(s -> s.getName())
.orElseGet(() -> returnDeault());
System.out.println(s2);
//传值为空的话会抛出指定异常
String s3 = Optional.ofNullable(student)
.map(s -> s.getName())
.orElseThrow(() -> new MyException("学生姓名为空"));
System.out.println(s3);
/**
* 方法
*/
public String returnDeault() {
System.out.println("执行了returnDeault方法");
return "未知";
}
返回值:
//① 返回student 为null时,orElse()跟orElseGet()都会执行
null
执行了returnDeault方法
未知
执行了returnDeault方法
未知
throw new MyException("学生姓名为空")// --抛出异常
//② 返回student 都有值时,只有orElse()会执行,orElseGet()不再执行
Student(name=张三, age=18, address=null)
执行了returnDeault方法
张三
张三
张三
③ filter() 如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional
Student student = createBody();
System.out.println(student);
Student student2 = Optional.ofNullable(student)
.filter(s -> s.getName() != null)
.orElseGet(()->{return new Student().setName("手动创建!");});
System.out.println(student2);
返回值:
//① 返回student 为null时,该值被过滤掉,转而返回 orElseGet() 创造的student
null
Student(name=手动创建!, age=null, address=null)
//② 返回student 都有值时,返回真实值
Student(name=张三, age=18, address=null)
Student(name=张三, age=18, address=null)
④ map() 如果有值,则对其执行调用mapping函数得到返回值,否则返回空Optional
上面例子中已使用过
Student student = createBody();
System.out.println(student);
String s1 = Optional.ofNullable(student)
.map(s -> s.getName())
.orElseGet("未知"::toString);
System.out.println(s1);
返回值
// 返回值为空
null
未知
// 返回值不为空
Student(name=张三, age=18, address=null)
张三
⑤ flatMap() 不自动封装的 map()
map和flatMap均要求optional对象非空才执行mapper方法,二者均返回Optional对象。
但是map会自动将计算结果封装为Optional对象,而flatMap需要自己进行封装。
举例
Student student = createBody();
System.out.println(student);
Optional<String> s1 = Optional.ofNullable(student)
.map(s -> s.getName()); //map() 的函数的返回值直接就可以是值的类型
Optional<String> s = Optional.ofNullable(student)
.flatMap(student1 -> Optional.ofNullable(student1.getName()));//flatMap() 的函数返回值需要处理一下
System.out.println(s1);
返回值一致,不再展示
– 完结 –