要说Java编程中哪个异常是你印象最深刻的,那NullPointerException空指针可以说是臭名昭著的。不要说初级程序员会碰到,即使是中级,专家级程序员稍不留神,就会掉入这个坑里。
零引用的发明者Tony Hoare曾在2009年作出道歉声明,声明中表示,到目前为止,空指针异常大约给企业已造成数十亿美元的损失。
下面是Tony Hoare的原话:
我将空引用的设计称为是一个数十亿美元的错误.1965那年,我正在用面向对象语言(算法W)设计首个功能全面的系统。当时我的考量是,确保所有被使用的引用都是安全的,编译器会自动进行检查。但是,我没有抵住诱惑,加入了零引用,仅仅是为了实现起来省事。这之后,它导致了数不清的错误,错误和系统崩溃,也为企业导致了不可估量的损失。
引用>事已至此,我们必须学会面对它,所以,我们要如何防止空指针异常呢?
唯一的办法就是对可能为零的对象添加检查。但是零检查是繁琐且痛苦的,所以一些比较新的语言为了处理零检查,特意添加了特殊的语法,如空合并运算符。
在Groovy或芬兰湾的科特林这样的语言中也被称为埃尔维斯运算符。
引用>不幸的是,在老版本的Java中并没有提供这样的语法糖.Java8中在这方面做了改进,所以,这篇文章就特意来介绍一下如何在Java8中利用新特性来编写防止NullPointerException的发生。
在上篇文章Java8新特性指导手册中简单的提了一下如何通过可选类来对对象做空校验。接下来,我们再细说一下:
在业务系统中,对象中嵌套对象是经常发生的场景,如下示例代码:
//最外层对象 类外{ 嵌套嵌套; 嵌套getNested () { 返回嵌套; } }//第二层对象 嵌套类{ 内内; 内部捷(){ 返回内; } }//最底层对象 类内部{ 字符串foo; 字符串getFoo () { 返回foo; } }业务中,假设我们需要获取外对象对底层的内心中的foo属性,我们必须写一堆的非空校验,来防止发生NullPointerException:
//繁琐的代码 外外=new外(); 如果(外!=零,,外。嵌套!=零,,outer.nested。内心!=null) { System.out.println (outer.nested.inner.foo); }
在Java8中,我们有更优雅的解决方式,那就是使用可选的是说,我们可以在一行代码中,进行流水式的地图操作。而图方法内部会自动进行空校验:
可选的。外()(新) . map(外::getNested) . map(嵌套::捷) . map(内心:getFoo .ifPresent (system . out:: println);//如果不为空,最终输出foo的值
上面这种方式个人感觉还是有点啰嗦,我们可以利用suppiler函数来出一个终极解决方案:
公共静态& lt; T>Optional解决(Supplier 解析器){ 尝试{ 结果T=resolver.get (); 返回Optional.ofNullable(结果); } 抓住(NullPointerException e) {//可能会抛出空指针异常,直接返回一个空的可选的对象 返回Optional.empty (); } } 利用上面的解决方法来重构上述的非空校验代码段:
外obj=new外();//直接调用解决方法,内部做空指针的处理 解决(()→.getFoo .getInner obj.getNested () () ()); .ifPresent (system . out:: println);//如果不为空,最终输出foo的值
你需要知道的是,上面这两个解决方案并没传统的零检查性能那么高效。但在绝大部分业务场景下,舍弃那么一丢丢的性能来方便编码,是完全可取,除非是那种对性能有严格要求的,我们才不建议使用。
个人觉得,真要拿这点性能说的事,还不如去优化优化sql语句,业务逻辑等。
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。
在Java8中如何风骚走位的避开空指针异常