点击上方蓝色“方志朋”,选择“设为星标”
回复“666”获取独家整理的学习资料!
本文来自作者投稿,原作者:上帝爱吃苹果
对于Java程序员来说,null是令人头痛的东西。时常会受到空指针异常(NPE)的骚扰。连Java的发明者都承认这是他的一项巨大失误。
那么,有什么办法可以避免在代码中写大量的判空语句呢?
有人说可以使用 JDK8提供的 Optional 来避免判空,但是用起来还是有些麻烦。
作者在日常工作中,封装了一个工具,可以可以链式调用对象成员而无需判空,相比原有的if null逻辑 和 JDK8提供的 Optional 更加优雅易用,在工程实践中大大提高了编码效率,也让代码更加的精准和优雅。
不优雅的判空调用
我想从事Java开发的小伙伴肯定有遇到过下面这种让人难受的判空逻辑:现在有一个User类,School 是它的成员变量
/***@authorAxin*@since-09-20*@summary一个User类定义*(Ps:Data 是lombok组件提供的注解,简化了get set等等的约定代码)*/@DatapublicclassUser{privateStringname;privateStringgender;privateSchoolschool;@DatapublicstaticclassSchool{privateStringscName;privateStringadress;}}
现在想要获得School的成员变量 adress , 一般的处理方式:
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());}}
获取adress时要对School进行判空,虽然有些麻烦,到也能用,通过 JDK8 提供的 Optional 工具也是可以,但还是有些麻烦。
而下文的 OptionalBean 提供一种可以链式不断地调用成员变量而无需判空的方法,直接链式调用到你想要获取的目标变量,而无需担心空指针的问题。
链式调用成员变量
如果用了本文设计的工具 OptionalBean ,那么上述的调用可以简化成这样:
publicstaticvoidmain(String[]args){Useraxin=newUser();User.Schoolschool=newUser.School();axin.setName("hello");//1.基本调用Stringvalue1=OptionalBean.ofNullable(axin).getBean(User::getSchool).getBean(User.School::getAdress).get();System.out.println(value1);}
执行结果:
其中User的school变量为空,可以看到代码并没有空指针,而是返回了null。这个工具怎么实现的呢?
OptionalBean 工具
/***@authorAxin*@since-09-10*@summary链式调用bean中value的方法*/publicfinalclassOptionalBean<T>{privatestaticfinalOptionalBean<?>EMPTY=newOptionalBean<>();privatefinalTvalue;privateOptionalBean(){this.value=null;}/***空值会抛出空指针*@paramvalue*/privateOptionalBean(Tvalue){this.value=Objects.requireNonNull(value);}/***包装一个不能为空的bean*@paramvalue*@param<T>*@return*/publicstatic<T>OptionalBean<T>of(Tvalue){returnnewOptionalBean<>(value);}/***包装一个可能为空的bean*@paramvalue*@param<T>*@return*/publicstatic<T>OptionalBean<T>ofNullable(Tvalue){returnvalue==null?empty():of(value);}/***取出具体的值*@paramfn*@param<R>*@return*/publicTget(){returnObjects.isNull(value)?null:value;}/***取出一个可能为空的对象*@paramfn*@param<R>*@return*/public<R>OptionalBean<R>getBean(Function<?superT,?extendsR>fn){returnObjects.isNull(value)?OptionalBean.empty():OptionalBean.ofNullable(fn.apply(value));}/***如果目标值为空获取一个默认值*@paramother*@return*/publicTorElse(Tother){returnvalue!=null?value:other;}/***如果目标值为空通过lambda表达式获取一个值*@paramother*@return*/publicTorElseGet(Supplier<?extendsT>other){returnvalue!=null?value:other.get();}/***如果目标值为空抛出一个异常*@paramexceptionSupplier*@param<X>*@return*@throwsX*/public<XextendsThrowable>TorElseThrow(Supplier<?extendsX>exceptionSupplier)throwsX{if(value!=null){returnvalue;}else{throwexceptionSupplier.get();}}publicbooleanisPresent(){returnvalue!=null;}publicvoidifPresent(Consumer<?superT>consumer){if(value!=null)consumer.accept(value);}@OverridepublicinthashCode(){returnObjects.hashCode(value);}/***空值常量*@param<T>*@return*/publicstatic<T>OptionalBean<T>empty(){@SuppressWarnings("unchecked")OptionalBean<T>none=(OptionalBean<T>)EMPTY;returnnone;}}
工具设计主要参考了 Optional 的实现,再加上对链式调用的扩展就是上述的OptionalBean。
getBean 其实是当变量为空时返回了一个 包装空值的 OptionalBean 对象,同时泛型的使用让工具更加易用。
使用手册
可以看到代码中也提供了和 Optional 一样的扩展方法,如 ifPresent()、orElse()等等:
publicstaticvoidmain(String[]args){Useraxin=newUser();User.Schoolschool=newUser.School();axin.setName("hello");//1.基本调用Stringvalue1=OptionalBean.ofNullable(axin).getBean(User::getSchool).getBean(User.School::getAdress).get();System.out.println(value1);//2.扩展的isPresent方法用法与Optional一样booleanpresent=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("地址存在:%s",adress)));//4.扩展的orElseStringvalue2=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("空指针了"));}catch(Exceptione){System.out.println(e.getMessage());}}
run一下:
总结
设计了一种可以链式调用对象成员而无需判空的工具让代码更加的精准和优雅,如果本文设计的工具满足了刚好解决你的困扰,那就在项目中使用吧!
工具推荐
大家可能不知道,囤茅台已经成为了一门生意!在很早之前,网上甚至还流传着这么一句话:买茅台股票还不如买上一车茅台酒屯着,这个玩意比金子还涨价快!
53 度飞天茅台官方指导出手价是 1499 元,但是正常情况下,1499 根本买不到,线下的专卖店可以买到 2000-3000 元左右,而且还容易买到假货!
相信很多人都知道,现在京东、苏宁、淘宝等各大网站都推出了茅台秒杀活动,以活动价格 1499 的价格进行抢购。
抢到就是赚到,二手市场茅台价格最低 2000 起,甚至会飙到 3000 左右,转手最少赚 500 元。
尤其是最近临近过年,茅台更成了畅销品。所以,很多人蹲守在各大网站,第一时间进行线上抢购。
现在抢购茅台,甚至已经成为了一个产业链,有人专门教大家怎么利用工具抢购茅台,抢购成功,一次收费 500 元!
开源抢茅台工具
已经有一位大神开发了一个抢购脚本,免费进行了开源,很多人都是使用这个脚本抢到了茅台。
看了一下它的实现思路,主要是这两种:
一种是利用 py 脚本模拟浏览器请求,来实现抢茅台。
另一种是通过 Chrome 插件来模拟用户点击行为,来实现抢茅台行为。
原作者分享的开源项目超过了 70K Star,但某种不知道的原因已经删除了。
由于备份的比较早,网上还存在着 2 份开源代码,对这份开源项目感兴趣的朋友,可以在下方公众号内回复:茅台。
开源项目获取方式
关注下方公众号
????????????
回复关键字「茅台」,即可下载