专栏首页维C果糖Guava 指南 之「使用和避免 null」

Guava 指南 之「使用和避免 null」

使用和避免null

null,糟糕透啦!” —— Doug Lea. “我称null为百亿美金的错误!” —— C. A. R. Hoare.

轻率地使用null可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受null作为元素,因此相比于默默地接受null,使用快速失败的操作拒绝null值对开发者更有帮助。

此外,null的模糊性会让人很不爽。我们很难知道返回值是null代表着什么意思,例如当Map.get(key)返回null时,既可能是 Map 中对应key的值是null,也可能是 Map 中根本就没有对应key的值。null可以表示成功,也可以表示失败,几乎意味着任何事情。使用除null之外的某些其他值,可以让你表达的含义更清晰。

在某些场景下,使用null也确实是正确的。例如,在内存和速度方面,null就是廉价的,而且在对象数组中,出现null也是不可避免的。但是相对于库来说,在应用代码中,null往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当Map.get(key)返回null时,既可能是 Map 中对应key的值是null,也可能是 Map 中根本就没有对应key的值。最关键的是,null根本就没有给出空值到底意味着什么。

正是由于这些原因,很多的 Guava 工具类都被设计为针对null是快速失败的,除非工具类本身对null是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用null时用起来更简单,也可以让我们避免使用null.

具体案例

不要在Set中使用null,也不要把null作为 Map 的键;在查询操作中,使用一个特殊值表示null,这会让我们的语言更加清晰。

如果你想使用null作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的Set更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为null的键到底有什么含义。

如果你在List中使用null,并且列表是稀疏的,那么使用Map<Integer, E>可能会更高效,并且可能更符合你潜在的需求。

此外,我们可以考虑一下使用自然的null对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示null。还例如,在java.math.RoundingMode里面有一个常量UNNECESSARY,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。

如果你确实需要使用null值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的Collections.unmodifiableList代替 Guava 中的ImmutableList.

Optional

一般情况下,我们使用null表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,Map.get就会返回null.

Optional<T>是一个用非空的值代替引用T有可能为空的方法。一个Optional可能包括非空的T引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,Optional绝不会说它包含null.

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

Optional不打算直接模拟其他编程环境中的option or maybe语义,尽管它们确实有些相似。

在这里,我们列出了一些最常见的Optional操作。

创建Optional实例

这里给出的都是Optional的静态方法。

方法

描述

Optional.of(T)

创建值非空的Optional实例,如果值为空则快速失败

Optional.absent()

返回某些类型引用缺失的Optional实例

Optional.fromNullable(T)

将可能为空的引用传入Option实例,如果引用非空则表示存在;引用为null,则表示缺失

查询方法

下面都是非静态的方法,因此需要特定的Optional<T>实例来调用。

方法

描述

boolean isPresent()

如果Optional包含非null的引用,则返回true

T get()

返回Optional所包含的实例,若引用缺失,则抛出java.lang.IllegalStateException

T or(T)

返回Optional所包含的引用,若引用缺失,返回指定的值

T orNull()

返回Optional所包含的引用,若引用缺失,返回null. 此为fromNullable的逆操作。

Set<T> asSet()

返回Optional所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。

除了上面给出的方法之外,Optional还提供了很多有用的工具方法,具体可以通过Javadoc来查看详细的资料。

使用Optional有什么意义?

除了增加null的可读性之外,Optional最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用null很容易让我们忽略某些情况,尽管FindBugs可以给我们提供帮助,但我们并不认为这种解决方法很好。

特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记other.method(a, b)可以返回一个空值,就像你在实现一个方法other.method的时候,你也可能忘记参数a可以是一个null值一样。而将方法的返回类型指定为Optional,也可以迫使调用者思考返回为引用缺失的情形。

便利的方法

当你想使用某些默认值代替一个null值的时候,可以使用MoreObjects.firstNonNull(T, T)方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为null,则会抛出NullPointerException异常。如果你使用Optional的话,这里有一个更好的替换方案,例如first.or(second)

Strings类中,也提供了很多可以处理String值可能为空的方法。特别得,我们提供了恰当的名称:

方法签名

emptyToNull(String)

isNullOrEmpty(String)

nullToEmpty(String)

我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如null字符串和空字符串等等。每当你写下混淆null和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和null字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!

翻译声明:本文翻译自 GitHub,Google Guava - UsingAndAvoidingNullExplained.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 设置 IntelliJ IDEA 主题和字体的方法

    1 前言 在博文「IntelliJ IDEA 之 HelloWorld 项目创建及相关配置文件介绍」中,我们已经用 IntelliJ IDEA 创建了第一个 J...

    CG国斌
  • 关于 toLocaleDateString 方法的实践分享

    示例代码如上所示,其结果就是:请求失败。至于原因嘛,tradeDate是object类型,而在 AJAX 中,object类型是不能直接与后台进行交互的,需要将...

    CG国斌
  • 二叉树的前序、中序、后序、层序以及蛇形遍历的实现方式

    如上述所示,蛇形层次遍历的顺序为:先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行。

    CG国斌
  • 关于 JavaScript 中 null 的一切

    JavaScript 有两种类型:原始类型(strings, booleans, numbers, symbols)和对象

    GopalFeng
  • 由null出发-看看为何mysql这么排斥null

    在表结构设计时我们经常会面对是否要加空值约束、默认值处理等问题,当向前人经验中检索时,经常会看到不建议为null,强刷面经时not null也经常被归结到优化建...

    邹志全
  • 3分钟短文 | PHP判断null,别再 == 了,你真控制不住

    PHP 程序中很多地方会用到判断是否为空,比如字符串为空,数组为空,对象为空,或者其他数据类型为默认空值。

    程序员小助手
  • JTable常见用法细则+设置某列可编辑+滚动表格

    JTable常见用法细则 JTable是Swing编程中很常用的控件,这里总结了一些常用方法以备查阅.欢迎补充,转载请注明作者与出处. 一. 创建表...

    YGingko
  • Android开发 - 处理 null 和 预防空指针异常(NullPointerException) 的一些经验

    比如: 通过intent传参到新的目标 activity,而且一定需要这个参数,那么在新的目标activity中 onCreate方法中 判断中这个参数,如果n...

    zhangyunfeiVir
  • Java中有关Null的9问题

    Java中有关Null的9问题 对于Java程序员来说,null是令人头痛的东西。时常会受到空指针异常(NPE)的骚扰。连Java的发明者都承认...

    用户1289394
  • 99%的高级程序员都这样使用null

    如果使用某个对象或对象里属性前先判断是否为null,那就需要思考一下你的代码是否已经烂掉了。 null是什么意思,你能说清楚它的意图吗?方法返回了null,是出...

    JavaQ

扫码关注云+社区

领取腾讯云代金券