使用Guava工具包处理null,避免null的使用 已翻译 100%

not3 投递于 2013/05/23 09:36 (共 8 段, 翻译完成于 08-12)
阅读 3043
收藏 4
1
加载中

粗心地使用null能导致一大堆bug。通过研究Google code base,我们发现大约95%的collection中不该含有null值。对于开发者来说,collection对null值如果能直接报错,会比默默接受更有帮助。

此外,null让人讨厌的一点在于它的含义模糊。函数返回值为null时,很少能让人明白是什么意思——比如,Map.get(key)返回null,可能是因为map中的值为null,也可能是因为map中没有对应的值。Null可以表示失败,可以表示成功,可以表示任何事情。想要表意清晰,就不要用null。

戴仓薯
翻译于 2014/01/31 16:55
4

虽然这么说,也有时候用null是正确的选择。null在时间和空间上的代价都很低,并且在object array中不可避免。但是相对于官方库,在实际应用的代码中,null仍然是导致迷惑不清、奇怪bug和表义模糊的主要原因之一。还是上面的例子,当Map.get返回null,可能说明不存在对应的值,也可能说明值存在且为null。最大的问题在于,null无法提示这个null值表示什么意思。

因此,很多Guava utility设计为对null值直接报错;只要有不用null的代替方案,就不允许null值。另外,Guava提供了一些工具来帮你避免使用null,同时在你不得不用时让使用null更容易。

戴仓薯
翻译于 2014/01/31 16:55
3

具体情况

如果你尝试在Set中使用null或者在Map中把null作为key传入,不要这么做!!!这是非常明确的(并不令人那么惊讶),即便你在查询操作中使用明确特殊情况的null。

如果你想把null作为值传入Map:不要考虑那entry;保持一个隔离的只包含not-null键值(或者null键值)的Set。Map含有这个键值所对应的值是null,Map的这个键值没有entry,这两种情况是非常容易混淆的。更好的方法是保持这些键值隔离开来,然后去考虑对你的应用来讲键值对应的值是null时意味着什么。

not3
翻译于 2013/07/29 17:08
1

假如你在一个List中使用了nulls,而且这个List是稀疏的,你使用Map是不是一个更好的选择?实际上这可能更有效,而且可能更精确得符合你应用的需求。

考虑有个天然的“null object“会被使用。这不常见,只是有时会。例如,假设有个enum,无论如何你期望null有含义,请添加一个常量去代表。例如,java.math.RoundingMode有一个UNNECESSARY的值代表“不要使之整数化,如果整数化是必须的则抛出异常”。

假如你真的需要null值,而且在使用对null不友好的集合实现遇到问题时,那么使用其他实现。例如,使用Collections.unmodifiableList(Lists.newArrayList())代替ImmutableList。

not3
翻译于 2013/07/29 17:08
1

Optional

程序员使用null代表一种消失的案例有很多:可能这里有值,它的值是none,或者这个值找不到了。例如,当一个键值所对应的值找不到,Map.get返回null。

Optional是一种使用非空值代替可以为空的T引用的方式。一个Optional可能含有一个非空T引用(这种情况下,我们称这引用是“存在的”),也可能不含有值(这种情况下,我们称这引用是“不存在的”)。它永远不会说“含有null”。

Optional<Integer> possible =Optional.of(5);<br>possible.isPresent();// returns true<br>possible.get();// returns 5
Optional不是任何存在的“选项”或者“可能”(从其他编程环境构建)的直接类似情况,尽管它必须忍受某种程度的类似。

我们这里列出一些最常用的Optional操作。

not3
翻译于 2013/07/29 17:09
1

构建一个 Optional

下面每一个都是Optional里的静态方法。

Optional.of(T) 构建一个Optional,它包含指定的非空参数值,如果参数为空则构建失败。
Optional.absent() 返回一个某种类型的代表不存在的Optional。
Optional.fromNullable(T) 把一个给定的可能为空的值转换为一个Optional,把非空值作为一个存在的值来处理,把null作为不存在来处理。

查询方法

这些都是非静态方法,属于一个具体的T类型的Optional实例。

boolean isPresent() 返回true,如果Optional中包含了一个非空的实例。
T get() 返回它所包含的T类型的实例,它必须是存在的;否则抛出一个IllegalStateException。
T or(T) 返回该Optional中存在的值,或者如果什么也没有,则返回指定的默认值。
T orNull() 返回该Optional中存在的值,或者如果什么也没有,则返回null。是fromNullable的反向操作。
Set<T> asSet() 返回一个不可变的单例的集合,包含了该Optional中的实例,如果有的话;否则返回一个空的不可变的结合。

除了这些以外,Optional还提供了几个更为实用的方法;详细情况请查看Javadoc。

lwei
翻译于 2013/08/12 09:50
1

意义何在?

除了给null值命名所带来的代码可读性的提高Optional最大的好处在于它是傻瓜式的。如果你想让你的程序通过编译,那么你就会被迫去积极地思考null代表了什么含义,因为你必须主动的从Optional中获取返回值,来回答这个问题。令人不安的是,简单的使用null会使你忘记思考null代表了什么含义,尽管FindBugs有些帮助,但是我们并不认为它能很好的解决这个问题。

当你的返回值不确定是否存在时,想清楚null值的含义尤其重要。 跟其他人一样,比起来当你自己去实现other.method(a, b)方法时,可能会忘记a参数可能是null值,你更有可能会忘记 other.method(a, b) 方法本身可能会返回一个null值。返回Optional使得调用者不太可能忘记这种情况,因为他们不得不从对象中解析返回值,才能使代码通过编译。

lwei
翻译于 2013/08/12 10:26
1

快捷方法

任何时候后你想用一个默认值来替代一个null值,你都可以使用Objects.firstNonNull(T, T)。从方法名可以看出,如果两个输入参数都是null,方法会执行失败并快速抛出一个NullPointerException。如果你想用其它方法,有几个更好的方法可供选择 -- 比如 first.or(second)。

有几个方法是用来处理可能为null值的字符串参数的。具体来说,我们提供了下面几个恰如其名的方法:

emptyToNull(String)
isNullOrEmpty(String)
nullToEmpty(String)

我们想要强调的是这些方法主要是为了:封装那些把null和空字符串视为等价的令人烦恼的方法,使之使用起来更和谐。每一次你在写代码时合并处理null和空字符串,Guava团队都会感到悲哀。(如果null和空字符串确实代表了不同的含义还好些,但是把它们作为相同的东西来处理,则透出令人不安的代码味道)

lwei
翻译于 2013/08/12 09:21
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(0)

返回顶部
顶部
返回顶部
顶部