好代码 ,坏代码
上QQ阅读APP看书,第一时间看更新

2.1 空值和本书中的伪代码惯例

在我们观察代码示例之前,解释本书中伪代码处理控制的惯例十分重要。

许多编程语言都有某个值(或引用/指针)缺失的概念。编程语言的内置方法往往使用空值(Null)。历史上,空值游走于两个极端之间:有时非常好用,有时又会带来难以置信的问题。

空值之所以有用,是因为某个事物不存在的情况经常出现:某个值未提供或者某个函数不能提供预期的结果。

空值之所以会带来问题,是因为一个值能不能为空并不总是显而易见的,工程师经常在访问变量之前忘记检查它是否为空。这往往导致出错。你以前可能见过NullPointerException(空指针异常)、NullReferenceException(空引用异常)或Cannot read property of null(无法读取空属性)等错误信息,次数或许比你记得的要多。

由于空值可能带来问题,因此你有时候会看到一些建议,倡导绝不使用它们,或者至少绝不会从函数中返回空值。这当然有助于避免空值的问题,但在实践中,遵循这个建议需要采用许多编程技巧。

幸运的是,近年来,“空值安全”〔也称为“无效值安全”(void safety)〕的思路越来越受到关注。这能确保任何可能为空的变量或返回值有相应的标识,编译器将强制要求必须事先检查其非空后才能使用。

近年来出现的大部分重要的新编程语言都支持空值安全。在C#等编程语言的较新版本中,也可以选择启用该功能,甚至有办法将其改造成类似Java这样的编程语言。如果我们使用的编程语言支持空值安全,那么利用这一特性可能是个好主意。

如果我们使用的编程语言不支持空值安全,那么使用可选类型来代替空值是比较好的做法。许多编程语言都支持这一特性,包括Java、Rust(称为Option)和C++(不过针对C++需要考虑一些细微的差别,我们在附录B中介绍)。即使在不以标准特性形式支持空值安全的编程语言中,往往也有增添这种支持的第三方工具。

本书中的伪代码惯例假设支持空值安全。默认情况下,变量、函数参数和返回类型都不可以是空值。但如果类型以“?”为后缀,就意味着它可以为空,编译器将不强制先检查其是为非空就可以使用。下面的代码片段展示了使用空值安全的伪代码:

Element? getFifthElement(List<Element> elements) {    ←---   Element?中的“?”表示返回类型可以为空
  if (elements.size() < 5) {
    return null;    ←---  当我们无法获得该值时返回空值
  }
  return elements[4];
}

如果我们使用的编程语言不支持空值安全,但是又想用可选类型编写这个函数,那么下面这个代码片段展示了改写的方法:

Optional<Element> getFifthElement(List<Element> elements) {    ←---  返回类型是可选元素
  if (elements.size() < 5) {
    return Optional.empty();    ←---  返回Optional.empty(),代替空值
  }
  return Optional.of(elements[4]);
}

如果你想了解更多关于空值安全和可选类型的知识,请参考附录B。