[Guava官方文档翻译] 2.使用和避免使用null (Using And Avoiding Null Explained)
本文地址:http://www.cnblogs.com/hamhog/p/3536647.html
"null很恶心。" -Doug Lea
"这是一个令我追悔莫及的错误。" - Sir C. A. R. Hoare, 在评价他对null的发明时说。
使用和避免使用null
粗心地使用null能导致各种各样的bug。通过研究Google code base,我们发现大约95%的collection中不该含有null值。对于开发者来说,collection对null值如果能直接报错,会比默默接受更有帮助。
此外,null让人讨厌的一点在于它的含义模糊。函数返回值为null时,很少能让人明白是什么意思——比如,Map.get(key)返回null,可能是因为map中的值为null,也可能是因为map中没有对应的值。Null可以表示失败,可以表示成功,可以表示任何事情。想要表意清晰,就不要用null。
虽然这么说,也有时候用null是正确的选择。null在时间和空间上的代价都很低,并且在object array中不可避免。但是相对于官方库,在实际应用的代码中,null仍然是导致迷惑不清、奇怪bug和表义模糊的主要原因之一。还是上面的例子,当Map.get返回null,可能说明不存在对应的值,也可能说明值存在且为null。最大的问题在于,null无法提示这个null值表示什么意思。
因此,很多Guava utility设计为对null值直接报错;只要有不用null的代替方案,就不允许null值。另外,Guava提供了一些工具来帮你避免使用null,同时在你不得不用时让使用null更容易。
具体情况
如果你想把null加进Set中,或者作为Map的key——那就不要这么做。如果你根据情况显式地替换掉null,查找结果的含义会更加清晰。
如果你想把null用作Map的value——那就不要添加对应的entry,而要把key存进用另外一个专门的Set里。到底是Map中对应这个key的value为null,还是Map没有这个key的entry,这两种情况非常容易弄混。把值为null和不为null的这两种key分开存就要好得多了,在跟value相关联的key是null的情况下更是如此。
如果你想把null加进 List 里——如果list比较稀疏,也许用 Map<Integer, E> 更合适?这样可能效率更高,可能实际上更符合程序的需求。
设想一下如果有一个现成的"null object"可供使用。一般是没有的,但也有例外。比如,向一个 enum 加入常量,就代表了null的含义。再比如,java.math.RoundingMode 有个 UNNECESSARY 值来表示“不要取整,如果需要取整就抛出异常”。
如果你真的需要null值,使用不支持null的collection实现有困难,那只能换用另一种collection实现。例如,用 Collections.unmodifiableList(Lists.newArrayList()) 替换 ImmutableList 。
Optional类
很多情况下程序员会用 null 值来代表某种缺失:也许这里本来应该有个值,但现在没有,或是找不到。例如,Map.get 返回 null 值表示找不到这个key对应的value。
Optional<T> 是一种用非null值来替换可null的 T 引用的解决方案。一个 Optional 类要么包含一个非null的 T 引用(这种情况称为引用“存在(present)”),要么什么也不包含(这种情况称为引用“缺失(absent)”)。Optional 类从来不会“包含null”。
Optional<Integer> possible = Optional.of(5);
possible.isPresent();// returns true
possible.get();// returns 5
Optional 类并非与其他语言中的"option"或"maybe"结构完全等同,尽管可能有些相似性。
我们在此列出了一些常见的 Optional 类操作。
创建Optional
以下均为 Optional 类的静态方法:
Optional.of(T) | 创建一个Optional实例,包含非null的给定引用T,如果T为null则直接报错。 |
Optional.absent() | 返回一个absent的Optional实例。 |
Optional.fromNullable(T) | 将有可能为null的引用T转换为Optional实例。如果T不为null则实例为present,T为null则实例为absent。 |
查询方法
以下均为具体 Optional<T> 实例上的非静态方法:
boolean isPresent() | 如果包含非null的T(为present)实例,则返回 true 。 |
T get() | 如果为present,返回包含的 T 实例;否则抛出 IllegalStateException 。 |
T or(T) | 如果为present,返回包含的 T 实例;否则返回指定的默认值。 |
T orNull() | 如果为present,返回包含的 T 实例;否则返回 null 。这个方法是 fromNullable 的逆过程。 |
Set<T> asSet() | 如果为present,返回不可变的单例(singleton) Set ,Set中包含 Optional 中包含的 T 实例;否则返回一个空的不可变set。 |
除此之外,Optional 类还提供一些更方便的工具方法;查询Javadoc了解细节。
有何意义?
使用 Optional 除了能给 null 起个名字而增强可读性,最大的好处是它的防呆性。它会强迫你主动考虑值缺失的情况,否则就不能通过编译,因为你将需要主动解包 Optional 类,针对情况处理。讨厌的null太容易让人忘记该处理的事情,尽管FindBugs对此有些帮助,我们认为它还不足以解决问题。
Optional 这个优点的一个典型体现,就在于函数返回值既有可能"存在"也有可能"缺失"时。你(及其他人)在调用一个方法other.method(a,b)时忘记返回值可能为null的可能性,比你编写这个方法时会忘记参数 a 有为null的可能性大得多。返回值类型为 Optional 就杜绝了调用者忘记处理返回值为null的可能,因为调用者需要把返回值从 Optional 中解包出来,才能编译通过。
便捷方法
只要你想把一个 null 值替换为某个默认值,就可以用Objects.firstNonNull(T, T)。这个方法的功能顾名思义,如果两个参数 T 都是null,则直接报错,抛出NullPointerException。如果你在用 Optional,还有更好的方法——例如 first.or(second)。
Strings 中有一组方法用来处理可能为null的 String 值。这些命名直白的方法具体如下:
emptyToNull(String) |
isNullOrEmpty(String) |
nullToEmpty(String) |
我们想要强调,这些方法最主要用来应对某些讨厌的API,它们把null String和空String("")等同处理。而每当你自己写出把null string和 "" 混合处理的代码,Guava团队都会哭泣。(如果这两者的含义显著不同,那还好一些。但是把它们当做完全一样的东西处理,是一种不幸很常见的代码坏味道。)
中文翻译自Guava官方文档:GuavaExplained - UsingAndAvoidingNullExplained 译者:戴仓薯
[Guava官方文档翻译] 2.使用和避免使用null (Using And Avoiding Null Explained)的更多相关文章
- [Guava官方文档翻译] 7. Guava的Immutable Collection(不可变集合)工具 (Immutable Collections Explained)
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3538666.html ,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体 ...
- [Guava官方文档翻译] 6. 用Guava辅助Throwable异常处理 (Throwables Explained)
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3537508.html ,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体 ...
- [Guava官方文档翻译] 5. Guava的Object公共方法 (Common Object Utilities Explained)
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3537367.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...
- [Guava官方文档翻译] 4. 使用Guava Ordering排序 (Ordering Explained)
本文地址:http://www.cnblogs.com/hamhog/p/3537233.html 示例 assertTrue(byLengthOrdering.reverse().isOrdered ...
- [Guava官方文档翻译] 3. 前置条件检查(Preconditions Explained)
本文地址:http://www.cnblogs.com/hamhog/p/3536964.html 前置条件检查 Guava提供了一些检查前置条件的utilities.我们强烈建议静态import这些 ...
- [Guava官方文档翻译] 1.Guava简介 (Introduction)
用户指南 Guava包含Google在Java项目中用到的一些核心库:collections, caching, primitives support, concurrency 库, common a ...
- Spring官方文档翻译(1~6章)
Spring官方文档翻译(1~6章) 转载至 http://blog.csdn.net/tangtong1/article/details/51326887 Spring官方文档.参考中文文档 一.S ...
- Flume官方文档翻译——Flume 1.7.0 User Guide (unreleased version)中一些知识点
Flume官方文档翻译--Flume 1.7.0 User Guide (unreleased version)(一) Flume官方文档翻译--Flume 1.7.0 User Guide (unr ...
- Flume官方文档翻译——Flume 1.7.0 User Guide (unreleased version)(二)
Flume官方文档翻译--Flume 1.7.0 User Guide (unreleased version)(一) Logging raw data(记录原始数据) Logging the raw ...
随机推荐
- git 快速入门(二)
一.引子 git代码托管的优秀工具之一, 其工作原理和svn截然不同.一旦拥有主干master分支权限, 只要在本地拉取主干分支, 可以随时随地切换分支. 它拥有众多优点,eg :支持在断网的情况下, ...
- eclipse jetty启动内存溢出
一.eclipse jetty启动内存溢出, 异常信息 Exception in thread "ConfigClientWorker-Default" java.lang.Out ...
- iOS调用系统通讯录获取姓名电话号码(转)
原文地址:http://blog.csdn.net/idoshi201109/article/details/46007125 OS调用系统通讯录获取姓名电话号码 (iOS 8.0 Xcode6.3可 ...
- mysql select 报错
代码片段: sql_url = "select * from webpage where url = '%s'" % b try: cursor.execute(sql_url) ...
- POJ_1365_Prime_Land
//懒得解释 #include <iostream> #include <cstring> #include <cmath> #include <cstdio ...
- Android手机中获取手机号码和运营商信息
代码如下: package com.pei.activity; import android.app.Activity; import android.os.Bundle; import androi ...
- iOS开发——新特性OC篇&Swift 2.0新特性
Swift 2.0新特性 转眼间,Swift已经一岁多了,这门新鲜.语法时尚.类型安全.执行速度更快的语言已经渐渐的深入广大开发者的心.我同样也是非常喜爱这门新的编程语言. 今年6月,一年一度 ...
- php开发环境以及插件的配置安装
目前网上提供的常用的PHP集成环境主要有AppServ.phpStudy.WAMP和XAMPP等软件
- linux 查看文件命令总结
linux 查看文件命令总结 1.cat 查看文件内容 选项-b 空白行不显示行号.-n,空白行显示 2.more 查看文件内容,通过空格键查看下一页 q键退出查看 3.less 和上同,多了方向键( ...
- 例3-12opencv设置ROI感兴趣区域
前面说了一堆,也不知道啥用,感觉也没说清楚,可能确实需要一些例子来显性表示一下,或者他们在当初出版书籍针对的人群已经有了对图像的基本认识,然而自己还是没有建立起来,往后看看吧,希望能比较清楚的自己处理 ...