当前位置: 首页 > 科技观察

你还在用if(obj!=null)做非空判断吗?带你快速上手对Optional的实战认识!

时间:2023-03-14 15:35:06 科技观察

1。前言相信很多朋友都对java的NPE(NullPointerException)所谓的空指针异常一头雾水。有大佬说“防止NPE,是程序员的基本素养。》但是修身就是修身,这也是我们程序员最头疼的问题之一,所以今天要尽可能的利用Java8的新特性Optional,尽可能的简化代码,高效的处理NPE(NullPointerException)2.理解Optional和use简单的说,Opitonal类是Java为了解决人们通常使用null!=obj来判断一个对象是否为空而让人头疼导致NPE(NullPointerException).,同时Optional的存在可以让代码更简单,更易读,写起来更高效。常规判断://objectperson//属性有名字,agePersonperson=newPerson();if(null==person){return"personisnull";}returnperson;UseOptional://objectperson//propertyhasname,agePersonperson=newPerson();returnOptional.ofNullable(person).orElse("personisnull");测试显示类Person代码(如果你有不了解的朋友明白了,你可以看看这个):(Stringname){this.name=name;}publicIntegergetAge(){returnage;}publicvoidsetAge(Integerage){this.age=age;}}接下来,让我们高效学习一下神奇的Optional类吧!2.1先创建Optional对象我们先打开Optional的内部,一探究竟,先抽取几个创建Optional对象的方法publicfinalclassOptional{privatestaticfinalOptionalEMPTY=newOptional<>();privatefinalTvalue;//我们可以看出两个构造方块都是privateprivate//表示我们不能出去创建一个Optional对象privateOptional(){this.value=null;}privateOptional(Tvalue){this.value=Objects.requireNonNull(value);}//这个静态方法粗略的创建了一个空包装值的对象,因为没有参数赋值publicstaticOptionalempty(){@SuppressWarnings("unchecked")Optionalt=(Optional)EMPTY;returnt;}//这个静态方法粗略的创建了一个非空包装值的对象,因为赋值publicstaticOptionalof(Tvalue){returnnewOptional<>(value);}//这个静态方法粗略的说如果参数值为空就创建一个空对象,如果不为空就创建一个带参数的对象publicstaticOptionalofNullable(Tvalue){returnvalue==null?empty():of(value);}}做一个简单的例子来说明上面的对应//1,创建一个包装对象whose值为空OptionalobjectOptionaloptEmpty=Optional.empty();//2.创建一个Optional对象,其包装对象值不为空OptionaloptOf=Optional.of("optional");//3.创建一个包装对象值Optional对象,允许为空或不为空。OptionaloptOfNullable1=Optional.ofNullable(null);OptionaloptOfNullable2=Ooptional.ofNullable("可选");我们大致分析了创建Optional对象的内部方法,然后正式进入Optional的学习和使用更多Java面试技术要点,在Java知音回复“面试题汇总”公众号2.2Optional.get()方法(返回对象的值)get()方法返回一个option的实例值源码:publicTget(){if(value==null){thrownewNoSuchElementException("Novaluepresent");}returnvalue;}即如果value不为空则返回,为空则抛出异常"Novaluepresent"一个简单的例子说明Personperson=newPerson();person.setAge(2);Optional.ofNullable(person).get();2.3Optional.isPresent()方法(判断是否为空)isPresent()方法会返回一个boolean类型值,如果对象不为空则为True,为空则为false源代码:publicBooleanisPresent(){returnvalue!=null;}简单示例展示:Personperson=newPerson();person.setAge(2);if(Optional.ofNullable(person).isPresent()){//写非空逻辑System.out.println("notempty");}else{//写空逻辑System.out.println("isempty");}2.4Optional.ifPresent()方法(判断是否为空返回函数)意思是如果对象不为空,则运行函数体源码:publicvoidifPresent(Consumerconsumer){//如果value不为空,则运行accept方法体if(value!=null)consumer.accept(value);}看例子:Personperson=newPerson();person.setAge(2);Optional.ofNullable(person).ifPresent(p->System.out.println("年龄"+p.getAge()));如果对象不为空,则会打印age,因为内部已经做了NPE(非空判断),所以不用担心空指针异常扩展知识点:熟练使用Java8中的Stream,让集合操作飞起来!2.5Optional.filter()方法(过滤对象)filter()方法大致意思是接受一个对象,然后有条件地过滤它,如果满足条件,则返回Optional对象本身,如果不满足,则返回一个空的Optional源码:publicOptionalfilter(Predicatepredicate){Objects.requireNonNull(predicate);//如果为空,直接返回thisif(!isPresent())returnthis;else//判断return本身是否为空可选的returnpredicate.test(值)?this:empty();}简单的例子:Personperson=newPerson();person.setAge(2);Optional.ofNullable(person).filter(p->p.getAge()>50);2.6Optional.map()方法(对象的二次封装)map()方法会对应Functional接口中的对象,进行二次操作,封装成一个新的对象,然后返回给Optional源码:publicOptionalmap(Functionmapper){Objects.requireNonNull(mapper);//如果为空则自己返回if(!isPresent())returnempty();else{//否则返回OptionalreturnOptional。ofNullable(mapper.apply(value));}}示例显示:Personperson1=newPerson();person.setAge(2);StringoptName=Optional.ofNullable(person).map(p->person.getName()).orElse("名称为空");2.7Optional.flatMap()方法(二次包装的Optional对象)map()方法会对应Optionalfunctional接口中的对象进行二次操作,封装成一个新的对象返回给Optional源码:publicOptionalflatMap(Function>mapper){Objects.requireNonNull(mapper);if(!isPresent())returnempty();else{returnObjects.requireNonNull(mapper.apply(value));}}示例:Personperson=newPerson();person.setAge(2);OptionaloptName=Optional.ofNullable(person).map(p->Optional.ofNullable(p.getName()).orElse("nameisempty"));2.8Optional.orElse()方法(空返回Object)常用的方法之一,该方法的意思是如果包装对象为空,则执行orElse方法中的值,如果不为空,则返回写入该对象的源码:publicTorElse(Tother){//不为空则返回value,为空则返回otherreturnvalue!=null?value:other;}2.9Optional.orElseGet()方法(为空则返回Supplier对象)这是和orElse很像,入参不同,入参为Supplier对象,为空则返回传入对象的.get()方法,不为空则返回当前对象的源码:publicTorElseGet(Supplierother){returnvalue!=null?value:other.get();}Instance:Optional>sup=Optional.ofNullable(Person::new);//调用get()方法,那么就会调用对象的构造方法,即得到真正的对象Optional.ofNullable(person).orElseGet(sup.get());老实说,我也对Supplier对象感到困惑。在网上简单搜索了一下,了解到Supplier也是一种创建对象的方式。简单的说,Supplier就是一个接口,类似于Spring的懒加载,声明后不会占用内存。只有在执行完get()方法后,才会调用构造函数来创建对象。创建对象的语法是SuppliersupPerson=Person::new;supPersonwhenneeded.get()就够了2.10Optional.orElseThrow()方法(为空则返回异常)我个人在实战中经常使用这个方法。方法的作用是,如果为空,就会抛出你定义的异常。如果不是,则将当前对象返回为空。在实战中,所有的异常都要处理好。为了代码的可读性,源码:publicTorElseThrow(SupplierexceptionSupplier)throwsX{if(value!=null){returnvalue;}else{throwexceptionSupplier.get();}}例子:这是实战源码//一个简单的查询Membermember=memberService.selectByPhone(request.getPhone());Optional.ofNullable(member).orElseThrow(()->newServiceException("没有查询相关数据"));2.11相似方法对比分析可能有朋友看到这里,如果没用过,会觉得orElse()和orElseGet()和orElseThrow()很像,map()和flatMap()很像哈哈哈,don不用担心,都是从这一步出来的,我总结一下不同方法的异同orElse()和orElseGet()和orElseThrow()方法效果差不多,如果对象不为空,则返回对象,而如果为空则返回方法体中对应的参数,所以可以看出三个方法体中的参数是不同的orElse(Tobject)orElseGet(Supplierobject)orElseThrow(异常)map()和orElseGet的异同点有相似的作用。方法参数重新打包返回。输入参数不同。定义了业务场景和代码规范,下面简单介绍一下我是如何在实战中使用神奇的Optional3的。实战场景复现场景一:在service层查询一个对象,返回后判断是否为空并做处理//查询一个对象Membermember=memberService.selectByIdNo(request.getCertificateNo());//使用Nullable加orElseThrow判断操作Optional.ofNullable(member).orElseThrow(()->newServiceException("没有查询相关数据"));场景二:我们可以在dao接口层定义返回值的时候加上Optional。比如:我用的是jpa,其他的也是一样publicinterfaceLocationRepositoryextendsJpaRepository{OptionalfindLocationById(Stringid);}当然是Service中的publicTerminalVOfindById(Stringid){//这个方法也包裹着dao层可选。OptionalterminalOptional=terminalRepository.findById(id);//直接用isPresent()判断是否为空if(terminalOptional.isPresent()){//用get()方法获取对象值Terminalterminal=terminalOptional.get();//在实战中,我们避免了使用set赋值的繁琐,直接使用BeanCopy赋值TerminalVOterminalVO=BeanCopyUtils.copyBean(terminal,TerminalVO.class);//调用使用dao层方法返回包裹后的对象;}returnterminalVO;}//别忘了抛出异常thrownewServiceException("Theterminaldoesnotexist");}4.Optional注意事项Optional真的好用吗,真的可以完全替代if判断吗?我想这一定是大家使用Optional之后可能会有的想法。答案是不。举个最简单的栗子:例1:如果我只想判断对象的某个变量是否为空,做判断怎么办?Personperson=newPerson();person.setName("");persion.setAge(2);//普通判断if(StringUtils.isNotBlank(person.getName())){//名字不为空执行代码block}//使用Optional做判断Optional.ofNullable(person).map(p->p.getName()).orElse("name为空");我觉得这个例子可以很好的说明这个问题,它只是一个很简单的判断,如果我们使用Optional,我们仍然需要考虑包装值、代码编写和方法调用。虽然只有一行,但可读性不好。如果其他程序员看了,我觉得肯定没有if5.jdk1.9首先加入三个Optional优化的方法那么明显:or()、ifPresentOrElse()和stream()or()类似于orElse等方法,如果对象不为空则返回对象,如果为空则返回or()方法中预设的值ifPresentOrElse()方法有两个参数:一个Consumer和一个Runnable。如果对象不为空,则执行Consumer的action,否则执行Runnable。与ifPresent()相比,多了OrElse判断。stream()将Optional转换为流,如果有值则返回包含该值的流,如果没有值则返回空流。因为我没有测试过jdk1.9的optional,发现有相当不错的文章可以让大家了解jdk1.9的option的优化,所以就不深入了。