Using and avoid null
“Null sucks.” -[Doug Lea]
“I call it my billion-dollar mistake.” - [Sir C. A. R. Hoare],
他对他自己发明的Null引用的评价
粗心的使用null
会造成各种惊人的bug。在学习了Google的代码基础之上,我们发现95%的collections都不会接收null值。使用快速失败而不是默默的接收null
对于开发者而言是更有帮助的。
除此之外,null
的歧义是让人很讨厌的。返回一个null
是很难判断出到底是什么意思。举个例子,Map.get(key)
返回null
的时候有可能是这个value放在map里面就是为null
,或者在Map里面就不存在也会返回null
。null
可以失败的意思,也可以代表成功,还可以代表很多意思。
有的时候正确的使用null
是很方便的,在内存和速度,还有在对象数组当中是无可避免的。但是在应用代码里面,和底层库里代码相反,null
是造成困惑,困难,怪异和有歧义且让人讨厌的主要来源。比如,Map.get
返回null,可以表示值不存在,也可以表示值存在但是为null
.更要批评的是,null没有给出任何空值的指示手段
综合这些原因,只要能够做到对null处理友好,许多Guava的工具类在遇到null的时候都被设计成快速失败而不是默默的执行。Guava还提供了大量的工具让使用null更加的容易和帮助你避免使用null
具体案例
如果你试图使用null
值在Set
或者作为key在Map
是使用–最好别这样做。如果在查询期间你很明确的表示了特殊的条件null
,那么null才会比较清晰一些。
如果你想用null
作为value放到Map里面,最好就是别放到Map里面。将非空的keys和null keys分开的放到不同的set里面。当Map里面的key是null的时候,很容易搞混到底是这个map里面没有key还是这个key的值就是空。最好的方式还是就是将null的key和非空的分开。然后思考对于你的应用而言当一个value的key为空的时候到底是什么意思。
如果你的List里面有很多的null,而且还都是离散的。更好的方式是使用Map<Integer,E>
,这样的效率更加的高而且可以更好的满足应用的需求
考虑到我们还是有对一个null object
的引用的使用方法,但是这种情况还是比较少。总是有特殊情况。比如,是一个枚举类,无论你希望null代表什么意思,都添加一个常量来表示null。例如,java.math.RoundingMode
就有一个UNNECESSARY
的值来表示"do no rounding,and throw an exception if rounding would be necessary."
如果你真的确确实实需要使用null值,使用非空的集合是有点问题,可以用一个其他的方法实现来替代,比如,使用Collections.unmodifiableList(Lists.newArrayList())
来代替ImmutableList
。
Optional
开发者使用null
的很多情况都是表示缺失,有可能有值,有可能没有,或者查找不到。比如,Map.get
在根据key去查找,找不到时就返回null
。
Optional<T>
是一种可以用非空的方式来代替之前的空T
的引用。使用Optional
要么包含一个非空的T
的引用(这种情况我们认为应用存在),要么什么也不包含(这种我们成为缺失)。这样就永远不会包含一个null。
Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5
Optional
不是和现有的Optional
直接类别,也不是从其他的编程环境构建而来。尽管有可能有很多相似之处。
我们列出了很多通用的Optional
的操作
使用Optional
下面的都是Optional
的静态方法
Method | Description |
---|---|
[Optional.of(T) ] | 创建一个Optional,包含一个非空的value。如果是null的就立刻失败。 |
[Optional.absent() ] | 创建引用缺失的Optional实例 |
[Optional.fromNullable(T) ] | 创建一个指定的Optional实例,如果引用为null就表示缺失 |
查询方法
下面的都是Optional<T>
的非静态方法
Method | Description |
---|---|
[boolean isPresent() ] | 如果Optional包含一个非空的引用,返回true |
[T get() ] | 返回Optional包含的T的引用,若引用缺失,则抛出java.IllegalStateException. |
[T or(T) ] | 返回Optional包含的引用,若引用缺失,返回指定的值. |
[T orNull() ] | 返回Optional包含的引用。若引用缺失,返回null |
[Set<T> asSet() ] | 返回Optional所包含引用的单例不可变集,如果引用存在,返回一个只有单一元素的集合,如果引用缺失,返回一个空集合。 |
Optional
除上面以外的其他的方法,可以查阅javadoc查看细节。
Optional意义在哪里
除了增加代码的可读性以外,最大的优势就是Optional
是一个傻瓜式的防护,它强迫你去积极的思考为null的情况。因为你必须显示的去Optional里面获取值。直接的使用null会让你很容易忘记某些事情。尽管我们可以通过FindBugs来帮我们检查,但是我们认为它还是不能很好的定位问题的根源。