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

不要再用if(obj!=null)来判断null了!_0

时间:2023-03-12 17:37:20 科技观察

1。在前言中,相信很多朋友都对java的NPE(NullPointerException)所谓的空指针异常一头雾水。有大佬说“防止NPE是程序员的基本修养”。但是修身归修身,也是我们程序员最头疼的问题之一。2.知道Optional并使用它简单的说,Opitonal类是Java为了解决人们通常使用null!=obj来判断一个对象是否为空而让人头疼导致NPE(NullPointerException)的判断而提供的空指针异常),Optional的存在可以让代码更简单,更易读,写起来更高效。例程判断://objectperson//attributehasname,agePersonperson=newPerson();if(null==person){return"personisnull";}returnperson;使用Optional://objectperson//attribute有个名字,agePersonperson=newPerson();returnOptional.ofNullable(person).orElse("personisnull");测试显示classPerson代码(不明白的可以看看这个):publicclassPerson{privateStringname;私人整数年龄;publicPerson(Stringname,Integerage){this.name=name;这个。年龄=年龄;}publicPerson(){}publicStringgetName(){返回姓名;}publicvoidsetName(Stringname){this.name=name;}publicIntegergetAge(){返回年龄;}publicvoidsetAge(Integerage){this.age=age;接下来,让我们高效地了解神奇的Optional类吧!2.1Optional对象的创建首先我们打开Optional的内部一探究竟。首先,提取几个创建Optional对象的方法。publicfinalclassOptional{privatestaticfinalOptionalEMPTY=newOptional<>();私有最终T值;//我们可以看到两个构造方块都是私有的private//说明我们没有方法出去创建一个Optional对象privateOptional(){this.value=null;}privateOptional(Tvalue){this.value=Objects.requireNonNull(value);}//这个静态方法粗略的创建了一个wrapper的对象,因为没有赋参数所以值为空publicstaticOptionalempty(){@SuppressWarnings("unchecked")Optionalt=(Optional)空的;返回吨;}//这个静态方法因为赋值publicstaticOptionalof(Tvalue){returnnewOptional<>(value);粗略的创建了一个非空包装值的对象}//这个静态方法粗略地说,如果参数值为空,则创建一个空对象,如果不为空,则创建一个带参数的对象publicstaticOptionalofNullable(Tvalue){return价值==空?空():(值);}}做一个简单的例子来显示与上面的对应。//1.创建一个Optional对象,其包装对象值为空OptionaloptEmpty=Optional.empty();//2.创建一个Optional对象,其包装对象值不为空OptionaloptOf=Optional.of("optional");//3.创建一个Optional对象,其值可以为空也可以不为空。OptionaloptOfNullable1=Optional.ofNullable(null);OptionaloptOfNullable2=Optional.ofNullable("optional");我们大致分析了创建Optional对象的内部方法。接下来,我们就正式进入Optional的学习和使用。2.2Optional.get()方法(返回对象的值)。publicTget(){if(value==null){thrownewNoSuchElementException("Novaluepresent");}returnvalue;}即值不为空则返回,为空则抛出异常"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("empty");}2.4Optional.ifPresent()方法(判断是否为空返回一个函数)this表示如果对象不为空,运行函数体源码:publicvoidifPresent(Consumerconsumer){//如果value不为空,运行accept方法体if(value!=null)consumer.accept(价值);}看例子:Personperson=newPerson();person.setAge(2);Optional.ofNullable(person).ifPresent(p->System.out.println("age"+p.getAge()));如果对象不为空,就会打印年龄,因为内部已经做了NPE(非空判断),所以不用担心空指针异常2.5Optional.filter()方法(过滤对象)的过滤器()方法大致意思是,接受一个对象,然后对其进行条件过滤,如果满足条件,则返回Optional对象本身,如果不满足,则返回一个空的Optional源代码:publicOptionalfilter(Predicatepredicate){Objects.requireNonNull(predicate);//如果为空,直接返回thisif(!isPresent())returnthis;else//判断return本身是否为空Optionalreturnpredicate.test(value)?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);//如果为空,则返回Selfif(!isPresent())returnempty();else{//否则返回用returnOptional.ofNullable(mapper.apply(value))方法修饰的Optional}}实例显示:Personperson1=newPerson();person.setAge(2);StringoptName=Optional.ofNullable(person).map(p->person.getName()).orElse("nameisempty");2.7Optional.flatMap()方法(Optional对象二次包装)map()方法会对应Optional功能接口中的对象,进行二次操作,封装成一个新的对象,然后返回源码在可选:publicOptionalflatMap(Function>mapper){Objects.requireNonNull(mapper);如果(!isPresent())返回空();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()方法的常用方法之一(为空返回对象),this方法的意思是如果包对象为空,则执行orElse方法中的值,如果不为空,则返回包对象的源码writtenobject:publicTorElse(Tother){//不为空则返回值,为空则返回其他返回值!=null?value:other;}示例:Personperson1=newPerson();person.setAge(2);Optional.ofNullable(person).orElse(newPerson("小明",2));2.9Optional.orElseGet()方法(为空则返回Supplier对象)这个和orElse很相似,入参不同,入参为Supplier对象,为空则返回Supplier对象的.get()方法传入对象,如果不为空,则返回当前对象源代码:publicTorElseGet(Supplierother){returnvalue!=null?值:other.get();}Instance:Optional>sup=Optional.ofNullable(Person::new);//调用get()方法,然后会调用对象的构造方法,即真正的对象Optional.ofNullable(person).orElseGet(sup.get());说实话,我对Supplier对象也是一头雾水,后来在网上简单搜索了一下,发现Supplier也是一种创建对象的方式。简单的说,Supplier就是一个接口,类似于Spring的懒加载。声明后不占用内存,只执行get()。方法之后,将调用构造函数来创建对象。创建对象的语法是SuppliersupPerson=Person::new;supPerson.get()可以在需要时使用。2.10选项nal.orElseThrow()方法(为空则返回异常)我个人在实战中经常使用该方法。方法的作用是,如果为空,就会抛出你定义的异常。如果不为空,则返回当前对象。实战中的所有异常都要处理好,为了代码源码的可读性:}else{抛出exceptionSupplier.get();}}例子:这是实战源码//一个简单的查询会员member=memberService.selectByPhone(request.getPhone());Optional.ofNullable(member).orElseThrow(()->newServiceException("没有查询相关数据"));2.11相似方法对比分析可能有朋友看到这里,如果没用过,会觉得orElse()和orElseGet()和orElseThrow()很像,map()和flatMap()很像哈哈哈别不用急,都是从这一步出来的,下面我总结一下不同方法orElse()和orElseGet()和orElseThrow()的异同方法效果的异同同理,如果对象不为空,则对象为返回,如果为空则返回方法体中对应的参数,所以可以看出三个方法体中的参数不同orElse(Tobject)orElseGet(Supplierobject)orElseThrow(异常)map()和orElseGet有相似的异同。方法参数重新打包返回。不同的入参map(functionfunction)flatmap(Optionalfunction)具体如何使用,根据业务场景和代码规范来定义。下面简单介绍一下我在实战中是如何使用神奇的Optional的。查询一个对象,返回后判断是否为空并处理//查询一个对象Membermember=memberService.selectByIdNo(request.getCertificateNo());//使用ofNullable加orElseThrow判断操作Optional.ofNullable(member).orElseThrow(()->newServiceException("没有要查询的相关数据"));场景二:我们可以在dao接口层定义返回值的时候加上Optional。比如:我用的是jpa,其他publicinterfaceLocationRepositoryextendsJpaRepository{OptionalfindLocationById(Stringid);}也是一样,然后在Service中publicTerminalVOfindById(Stringid){//这个方法也是用Optional在dao层包裹OptionalterminalOptional=terminalRepository.findById(id);//直接使用isPresent()判断是否为空if(terminalOptional.isPresent()){//使用get()方法获取对象值//在实战中,我们避免了使用set赋值的繁琐,直接使用BeanCopy为TerminalVO赋值terminalVO=BeanCopyUtils.copyBean(terminal,TerminalVO.class);//调用dao层方法返回包装后的对象Optionallocation=locationRepository.通过Id查找位置(terminal.getLocationId());如果(location.isPresent()){terminalVO.setFullName(location.get().getFullName());}返回终端VO;}//别忘了抛出异常thrownewServiceException("TheterminalDoesnotexist");}实战场景还是很多的,包括返回的时候判断是返回当前值还是跳转到另一个方法体。还有很多其他的事情。没有经验想学习的可以评论,我会回复大家4.使用Optional的注意事项真的好用吗,真的能完全代替if判断吗?我想这一定是大家使用Optional之后可能会有的想法。答案是不。举个最简单的栗子:例1:如果我只想判断对象的某个变量是否为空,做判断怎么办?Personperson=newPerson();person.setName("");persion.setAge(2);//普通判断if(StringUtils.isNotBlank(person.getName())){//名字不为空执行代码块}//用Optional做判断Optional.ofNullable(person).map(p->p.getName()).orElse("name为空");我觉得这个例子可以很好的说明这个问题,只是一个判断就很简单了。如果我们使用Optional,我们还需要考虑包装值、代码编写和方法调用。虽然只有一行,但可读性不好。如果其他程序员看了,我觉得一定没有if看。显然五、jdk1.9首先在Optional优化中加入了三个方法:or()、ifPresentOrElse()和stream()or()类似orElse等方法,如果对象不为空,则返回对象,如果为空为空,返回或()方法预设值。ifPresentOrElse()方法有两个参数:Consumer和Runnable。如果对象不为空,则执行Consumer的action,否则执行Runnable。与ifPresent()相比,多了OrElse判断。stream()将Optional转换为流,如果有值则返回包含该值的流,如果没有值则返回空流。因为我没有测试过jdk1.9的optional,发现有相当不错的文章可以让大家了解jdk1.9的option的优化,所以就不深入了。