所谓NPE(NullPointerException) 就是空指针异常,一般当我们访问一个为null的对象的属性或方法时会触发这个异常。一般来说,抛出NPE错误并不是用户操作的错误,而是开发人员的错误,是应该要避免的!然而,一直以来,为避免NPE所进行的繁琐的空指针判断让很多开发人员对它深恶痛绝,尤其当对象是一个嵌套较深的的复杂对象时更是如此。
空指针检查不可避免地带来了严重的不必要的精力损耗,而且,处处可见的非空检查严重影响了程序的可读性和可维护性。所以,避开null检查或优雅简洁地进行null检查是每一个有追求的开发人员的必备技能。
在避开null检查方面,前辈们已经总结了不少实用的经验,比如从已知的对象中调用方法、使用null安全的第三方类库(如Apache commons)等。然而,在很多时候,null检查是非做不可的事情,这时候如果能简化检查过程便是一件非常幸福的事情,好在最新的编程语言已经为我们提供了这方面的一些支持特性,比如下面要介绍的空传播机制。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ "students": [ { "name": "张三", "age": 18 }, { "name": "李四", "age": 17 } ] } |
假设有个接口,返回的响应像上面这样的,那么在使用时某个学生的年龄属性时,我们可能会这样写:
1 2 3 4 5 6 |
Integer age = 0; if(response!=null && response.students!=null && response.students.get(0)!=null && response.students.get(0).age!=null){ age = response.students.get(0).age; } |
在C#6.0中新增了空传播运算符(?.),对我们改进代码质量提高开发效率有很大的帮助,可以简化代码提升可读性,并将整个方法的复杂性降低。将上面代码使用这种方法改写后如下:
1 2 |
int age = response?.students?.get(0)?.age??0; |
这样看起来代码简洁了很多,非常优雅。
比较遗憾的是,java中并没有这么一个高逼格的空传播运算符,但是在java8中出现了一个Optional
1 2 3 4 5 6 |
Integer age = Optional.ofNullable(response) .map(response->response.students) .map(students->students.get(0)) .map(student->student.age) .orElse(0); |
看上去比C#的代码复杂不少,但是也较之前简洁不少。map方法在容器为空(存的对象是null)的情况下会直接返回空的Optional,最后,orElse方法在容器为空的情况下返回指定的值。
可能有些同学也会有这种写法:
1 2 3 4 5 6 7 8 9 10 |
Integer age = 0; try{ age = response.students.get(0).age; if(age==null){ age = 0; } }catch(NullPointerException e){ // do nothing } |
但是这种用法明显效率低,而且众所周知,不要catch NPE ! 所以可是使用新特性来改善代码的质量。