- 案例引入
- 使用`Optional`解决问题
- 如何使用Opptional避免空指针异常
用于解决容易引发空指针异常对象的操作方法 案例引入
比如一个套娃包装类电脑中的声卡中的usb中的Version(版本)
编写方法--要求实现传入computer对象,返回其声卡上的usb上的版本
如果不存在,返回UNKNOWN
public static String getVersion(Computer com){
String v=com.getSoundcard().getUsb().getVersion();
return v=null?"UNKNOW":v;//会出现什么问题?
}如果声卡中没有Usb,相当于空引用,空引用调用获得声卡方法会抛出异常
那么应该怎么写呢?
public static String getVersion(Computer com){
String version ="UNKNOW";
if(com!=null){
Soundcard sound=com.getSoundcard();//变量大驼峰,方法小驼峰
}
if(soundcard!=null){
Usb usb=soundcard.getUsb();
}
if(usb!=null){
Version version =soundcard.getVersion();
}
rerurn version;
}
多个if语句判断对象是否为空的情况时,会产生大量的冗余与业务逻辑无关的代码,而且任何一处没有检测是否可能为空指针都有可能引起运行时空指针异常
上面那个例子的业务逻辑就是从电脑中拿到声卡中的usb版但有复杂的空指针判断语句
Optional-----为解决空引用异常而引入的,用于封装单值元素的容器--single-valuecontainer--类比集合封装元素与流中的一些操作
在java.util.Optional
基于Optional提供的一系列方法,操作封装在容器中的,可能引起空引用的元素对象
容器中是否有元素?容器对象始终是存在的,当对容器对象进行操作时不会引起空指针异常,只是其中不一定有元素
创建容器---容器的一些方法 ofNullable() 执行操作--基于容器是否为空,执行操作无返回值 ifPresent() ifPresentOrElse() 中间操作,将操作结果置于新容器中以执行后续操作,结果为空,也会返回相同类型的空容器---怎么跟流一样,就是瓶子包装水,没水瓶子也存在这样吗,然后就有利于避免空指针异常 fiter() map() or() ------需手动创建容器注入 ?、? 获取操作,获取容器中对象 orElse() orElseGet() get() 判断方法 isEmpty() isPresent()
创建容器--基于可能为空的对象创建一个容器 Optionalop =Optional.ofNullable(null);出错 Optional op =Optional.ofNullable(new Computer()); 当容器不为空时,执行指定函数,为空忽略执行,容器中元素注入操作 private static void ifPresentOrElse(USB usb){ Optional usbOP=Optional.ofNullable(usb); usbOP.ifPresent(u->System.out.println(u.getVersion()));//非空注入,相当于传给执行语句 类似流的连续写法 Optional.ofNullable(usb) .ifPresent(u->System.out.println(u.getVersion()));//空的话下半部分不执行 Optional.ofNullable(new Computer())//无法避免内部空指针 .ifPresent(c->System.out.println(....())); } java 9加入了带两个参数的 ifPresent(,)有执行左面函数,无执行右面的函数 Optional or(),容器为空,执行函数,且必须返回一个,相同类型的容器,可以为空容器(java9的方法)
Optionalmap(),基于容器中的对象映射。容器为空返回同类型的空容器,容器不为空,执行映射函数,将映射结果封装在新容器中,即无论是否匹配均返回一个容器,用于后续操作 Optional.ofNullable(usb) .map(USB::getVersion)//转化为这种容器 .ifPresent(System.out::println);
需求,打印USB版本,如果版本为UNKNOW创建USB1.1打印不为UNKNOW直接打印
or ----容器为空,执行函数,且必须返回一个,相同类型的容器,可以为空容器
Optional.ofNullable(usb)
.filter(u->!"UNKNOW".equals(u.getVersion()))
.or(()->{
return Optional.of(new USB("1.1"));
})
.ifPresent(u->System.out.println(u.getVersion());});
终止操作 T orElse() orElseGet()
返回容器中对象,容器为空创建默认对象代替
orElse()---无论是否为空创建默认对象但是容器不空返回容器内对象为空返回创建的对象,orElse也实现前面有一次不成功得到空就可以返回创建的新对象,避免了多次判空,判断能力强
String v2=Optional.ofNullable(usb)
.orElse(new USB("1.1"))
.getVersion();
主函数如下
package com.experiment05.test;
import com.experiment05.entity.College;
import com.experiment05.entity.Student;
import com.experiment05.entity.Teacher;
import com.experiment05.resource.DatabaseUtils;
import java.util.List;
import java.util.Optional;
public class Test {
public static void main(String[] args) {
System.out.println(getCollegeName(DatabaseUtils.getStudents(), 888888));
printCollegeName(DatabaseUtils.getStudents(), 201001, 8888888);
}
private static String getCollegeName(List students, int sNumber) {
return students.stream()
.filter(s -> s.getNumber() == sNumber)
.findFirst()
.map(Student::getTeacher)
.map(Teacher::getCollege)
.map(College::getName)
.orElse("未知学院");
}
//也可调用容器类的方法传入对象直接封装生成容器,也可流封装产生容器
//学生可以直接调用自己的私有变量,注意在其它包中只能使用方法调用
private static void printCollegeName(List students, int sNumber, int tNumber) {
System.out.println(students.stream()
.filter(s -> s.getNumber() == sNumber)
.findFirst()
.map(Student::getTeacher)
.filter(t -> t.getNumber() == tNumber)//还有在到达这个对象的容器后再判断,如果空容器正好跳过,非空才有必要进行下一步过滤
.map(Teacher::getCollege)
.map(College::getName)
.orElse("未知学院"));//注意到orElse的作用,只要前面出现空直接断开到达orElse 容器返回默认对象
}
}
注意在另一个包中使用该对象无法使用私有变量,复习一下,但可以调用公有方法使用成员变量



