Optional类判空操作——一看就会


在开发过程中,经常会遇到判空的情形,若是不处理很有可能出现异常。但是进行的判空代码又冗余,且有时候出现级联判空的时候代码不太优雅。而jdk8中的Optional类正在处理空指针异常的新增类。

Optional类可以理解为一个容器,它可以存null,也可以存非null对象。

1、Optional类的基本使用
//创建2个学生对象,一个为非null,一个为null
Student student1 = new Student();
student1.setAge("26");
student1.setCity("wuhan");
student1.setSName("qsm");

Student student2 = null;

//创建Optional类对象
Optional<Student> optionalStudent1 = Optional.of(student1);
//Optional<Student> optionalStudent1 = Optional.of(student2); //报错:java.lang.NullPointerException
Optional<Student> optionalStudent2 = Optional.ofNullable(student2);//Optional.empty

//直接获取
System.out.println(optionalStudent1.get());//Student(sName=qsm, identityNum=null, age=26, city=wuhan)
//System.out.println(optionalStudent2.get());//报错:java.util.NoSuchElementException: No value present

//判空获取或者说是条件获取
//orElse是为空则返回后面逻辑的返回值;orElseGet一样,只不过是方法里可以写其他逻辑;orElseThrow,空则直接返回异常
System.out.println(optionalStudent1.orElse(new Student()));//Student(sName=qsm, identityNum=null, age=26, city=wuhan)
System.out.println(optionalStudent2.orElse(new Student("hn")));//Student(sName=hn, identityNum=null, age=null, city=null)

System.out.println(optionalStudent1.orElseGet(new Supplier<Student>() {
    @Override
    public Student get() {
        return new Student("liuqiangdong");
    }
}));//Student(sName=qsm, identityNum=null, age=26, city=wuhan)  下面一种方法为lambda简写
System.out.println(optionalStudent1.orElseGet(() -> new Student("liuqiangdong")));//Student(sName=qsm, identityNum=null, age=26, city=wuhan)
System.out.println(optionalStudent2.orElseGet(() -> new Student("mayun")));//Student(sName=mayun, identityNum=null, age=null, city=null)

System.out.println(optionalStudent1.orElseThrow(BizException::new));//Student(sName=qsm, identityNum=null, age=26, city=wuhan)
System.out.println(optionalStudent1.orElseThrow(()-> new BizException("3000","该学生为null")));//Student(sName=qsm, identityNum=null, age=26, city=wuhan)
//System.out.println(optionalStudent2.orElseThrow(BizException::new));//Exception in thread "main" com.jd.ins.qsm.demo.web.commom.excption.BizException

// filter()和 map()
Student student3 = new Student();
student3.setAge("18");
student3.setCity("beijing");
student3.setSName("hn");

List<Student> studentList = Lists.newArrayList();
studentList.add(student1);
studentList.add(student3);

// filter(),如果 Optional 对象有值且满足条件则返回原来的Optional 对象,否则返回空的Optional对象
Optional<List<Student>> optionalStudentList1 = Optional.ofNullable(studentList);
System.out.println(optionalStudentList1.filter(tempOptionalStudentList -> tempOptionalStudentList.size() > 1).orElse(Lists.newArrayList()));
//[Student(sName=qsm, identityNum=null, age=26, city=wuhan), Student(sName=hn, identityNum=null, age=18, city=beijing)]
Optional<List<Student>> optionalStudentList2 = Optional.ofNullable(null);
System.out.println(optionalStudentList2.filter(tempOptionalStudentList -> tempOptionalStudentList.size() > 1).orElse(Lists.newArrayList()));//[]

//map(), 如果Optional对象的值存在,执行 mapper 映射函数,返回函数返回的新的optional对象,否则返回空的Optional对象
Optional<List<Student>> students = optionalStudentList1.map(tempOptionalStudentList -> {
    for (Student student : tempOptionalStudentList) {
        student.setAge("99");
    }
    return tempOptionalStudentList;
});
System.out.println(students.get());//[Student(sName=qsm, identityNum=null, age=99, city=wuhan), Student(sName=hn, identityNum=null, age=99, city=beijing)]
System.out.println(optionalStudent1.map(student -> student.getAge()).get());//99


//如果存在ifPresent
optionalStudent1.ifPresent(new Consumer<Student>() {
    @Override
    public void accept(Student student) {
        student.setIdentityNum("1234");
    }
});
System.out.println(optionalStudent1.get());//Student(sName=qsm, identityNum=1234, age=99, city=wuhan)
optionalStudent2.ifPresent(student -> student.setIdentityNum("456"));//不会执行
//System.out.println(optionalStudent2.get());//java.util.NoSuchElementException: No value present
2、实际使用

在实际开发中,经常遇到2种情形:
第一个是级联判空经常出现;第二个某字段必须存在值,否则需要报错。
下面例子中,老师类里面有一个地址类的字段

private static void compare() throws Throwable {

Address address = new Address();
address.setCity("wuhan");

Teacher1 teacher1 = new Teacher1();
teacher1.setTName("qsm老师");
teacher1.setAddress(address);

//原来的级联判空
if (ObjectUtils.isNotEmpty(teacher1) && ObjectUtils.isNotEmpty(teacher1.getAddress())) {
    System.out.println(teacher1.getAddress().getCity());//wuhan
}

//使用Optional
//下面为简写,与上面一致
Optional.ofNullable(teacher1).map(Teacher1::getAddress).map(Address::getCity).orElse(null);//wuhan
//Optional.ofNullable(teacher1).map(tempTeacher -> tempTeacher.getAddress()).map(tempAddress -> tempAddress.getCity()).orElse(null);


//若程序中某个字段必须非空,否则需要抛出异常
//原来方法
if (ObjectUtils.isEmpty(teacher1) || ObjectUtils.isEmpty(teacher1.getAddress()) || ObjectUtils.isEmpty(teacher1.getAddress().getProvince())) {
    throw new BizException("32", "省份不存在");
}

Optional.ofNullable(teacher1).map(Teacher1::getAddress).map(Address::getProvince).orElseThrow(() -> new BizException("32", "省份不存在"));
//com.jd.ins.qsm.demo.web.commom.excption.BizException: 省份不存在
}

还有一种使用方法可以点击查看
Optional联合Stream使用——集合判空或取值

3、map和flatMap区别

简单而言:map的返回值会自动被包装为Optional对象。而flatMap则需要手动封装。具体请参考JDK8的Optional类中map方法和flatMap方法的区别

4、思考

Optional可以有效的解决空指针异常的问题。

同时也有一些问题需要注意,第一个是代码量并没有很有效的减少,第二个是判空也只是null的判空,对于字符串的空字符,集合的空元素等有待优化。

总体而言,Optional可以作为辅助手段进行代码的编写。





【正在去BAT的路上修行!!!】
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值