zoukankan      html  css  js  c++  java
  • [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   译者:戴仓薯

  • 相关阅读:
    leetcode 29-> Divide Two Integers without using multiplication, division and mod operator
    ros topic 发布一次可能会接收不到数据
    python中的print()、str()和repr()的区别
    python 部分函数
    uiautomatorviewer错误 unable toconnect to adb
    pyqt 不规则形状窗口显示
    appium 计算器demo
    Spring 3.0 注解注入详解
    Spring Autowire自动装配
    restful 学习地址
  • 原文地址:https://www.cnblogs.com/hamhog/p/3536647.html
Copyright © 2011-2022 走看看