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

请不要再使用!=null了!

时间:2023-03-21 19:33:36 科技观察

本文由作者投稿,原作者:上帝爱苹果对于Java程序员来说,null是个头疼的问题。经常被NullPointerException(NPE)骚扰。甚至Java的发明者也承认这是他的一个巨大错误。那么,有什么办法可以避免在代码中写大量的空判断语句呢?有人说可以使用JDK8提供的Optional来避免空判断,但是使用起来还是有点麻烦。作者在日常工作中,封装了一个可以链式调用对象成员而不判断null的工具。与JDK8提供的原始ifnull逻辑和Optional相比,更加优雅易用,大大提高了工程实践中的编码效率,也让代码更加精准优雅。空调的不雅判断我想搞Java开发的朋友一定遇到过下面这种难受的判断逻辑:现在有一个User类,School是它的成员变量/***@authorAxin*@since2020-09-20*@summaryA用户类定义*(ps:data是lombok组件提供的注解,简化了getset等契约代码)*/@DatapublicclassUser{privateStringname;privateStringgender;privateSchoolschool;@DatapublicstaticclassSchool{privateStringscName;privateStringadress;}}现在想获取School的成员变量address,一般处理方法:publicstaticvoidmain(String[]args){Useraxin=newUser();User.Schoolschool=newUser.School();axin.setName("hello");if(Objects.nonNull(axin)&&Objects.nonNull(axin.getSchool())){User.SchooluserSc=axin.getSchool();System.out.println(userSc.getAdress());}}获取地址时虽然判断学校有点麻烦,但也可以用。JDK8提供的Optional工具也是可以的,但是还是有点繁琐。下面的OptionalBean提供了一种方法,可以在不进行空判断的情况下,链式连续调用成员变量,直接链式调用你想要获取的目标变量,不用担心空指针的问题。如果本文设计的可选bean工具用于链式调用成员变量,那么上述调用可以简化为:publicstaticvoidmain(String[]args){Useraxin=newUser();User.Schoolschool=newUser.School();axin.setName("你好");//1.基本调用Stringvalue1=OptionalBean.ofNullable(axin).getBean(User::getSchool).getBean(User.School::getAdress).get();System.out.println(value1);}执行结果:用户的学校变量是空的,可以看到代码没有空指针,而是返回null。这个工具是如何实现的?OptionalBean工具/***@authorAxin*@since2020-09-10*@summary链式调用bean中value的方法*/publicfinalclassOptionalBean{privatestaticfinalOptionalBeanEMPTY=newOptionalBean<>;();privatefinalTvalue;privateOptionalBean(){this.value=null;}/***一个空值会抛出一个空指针*@paramvalue*/privateOptionalBean(Tvalue){this.value=Objects.requireNonNull(value);}/***包装一个bean不能为空*@paramvalue*@param*@return*/publicstaticOptionalBeanof(Tvalue){returnnewOptionalBean<>(value);}/***包装一个可能为空的bean*@paramvalue*@param*@return*/publicstaticOptionalBeanofNullable(Tvalue){returnvalue==null?empty():of(value);}/***获取特定值*@paramfn*@param*@return*/publicTget(){returnObjects.isNull(value)?null:value;}/***检索一个可能为空的对象*@paramfn*@param*@return*/publicOptionalBeangetBean(函数fn){returnObjects.isNull(value)?OptionalBean.empty():OptionalBean.ofNullable(fn.apply(value));}/***若目标值为空则获取默认值*@paramother*@return*/publicTorElse(Tother){returnvalue!=null?value:other;}/***如果目标值为空,通过lambda表达式获取一个值*@paramother*@return*/publicTorElseGet(Supplierother){returnvalue!=null?value:other.get();}/***如果目标值为null则抛出异常*@paramexceptionSupplier*@param*@return*@throwsX*/publicTorElseThrow(SupplierexceptionSupplier)throwsX{if(value!=null){returnvalue;}else{throwexceptionSupplier.get();}}publicbooleanisPresent(){returnvalue!=null;}publicvoidifPresent(Cons;?superT>consumer){if(value!=null)consumer.accept(value);}@OverridepublicinthashCode(){returnObjects.hashCode(value);}/***nullconstant*@param*@return*/publicstaticOptionalBeanempty(){@SuppressWarnings("unchecked")OptionalBeannone=(OptionalBean)EMPTY;returnnone;}}工具设计主要是参考了Optional的实现,加上链式调用的扩展,上面的OptionalBeangetBean其实就是变量为空的时候返回一个包装空值的OptionalBean对象,泛型的使用让工具更易用。在手册中可以看到代码也提供了和Optional一样的扩展方法,比如ifPresent(),orElse()等:publicstaticvoidmain(String[]args){Useraxin=newUser();User.Schoolschool=newUser.School();axin.setName("你好");//1.基本调用Stringvalue1=OptionalBean.ofNullable(axin).getBean(User::getSchool).getBean(User.School::getAdress).get();System.out.println(value1);//2.扩展的isPresent方法的用法与O??ptionalbooleanpresent=OptionalBean.ofNullable(axin).getBean(User::getSchool).getBean(User.School::getAdress).isPresent();System.out.println(present);//3.扩展ifPresent方法OptionalBean.ofNullable(axin).getBean(User::getSchool).getBean(User.School::getAdress).ifPresent(adress->System.out.println(String.format("Addressexists:%s",地址)));//4.ExtendedorElseStringvalue2=OptionalBean.ofNullable(axin).getBean(User::getSchool).getBean(User.School::getAdress).orElse("蹲在家里");System.out.println(value2);//5.扩展orElseThrowtry{Stringvalue3=OptionalBean.ofNullable(axin).getBean(User::getSchool).getBean(User.school::getAdress).orElseThrow(()->newRuntimeException("Nullpointer"));}catch(Exceptione){System.out.println(e.getMessage());}}运行一下:总结设计一个工具,可以不带空判断的链式调用对象成员,让代码更加精准优雅。如果本文设计的工具足以解决你的问题,那就在项目中使用吧!如果大家有更多的设计或者有错误的地方,欢迎大家留言一起讨论,共同进步!【本文为专栏作家霍利斯原创文章,作者微信公众号Hollis(ID:hollishuang)】点此阅读更多本作者好文