开源中国

我们不支持 IE 10 及以下版本浏览器

It appears you’re using an unsupported browser

为了获得更好的浏览体验,我们强烈建议您使用较新版本的 Chrome、 Firefox、 Safari 等,或者升级到最新版本的IE浏览器。 如果您使用的是 IE 11 或以上版本,请关闭“兼容性视图”。
代码异味:Null - 技术翻译 - 开源中国社区

代码异味:Null 【已翻译100%】

英文原文:Code Smells: Null
标签: <无>
oschina 推荐于 1个月前 (共 17 段, 翻译完成于 08-16) 评论 0
收藏  
1
推荐标签: 待读

【小编注:Code Smell 中文译名一般为“代码异味”,或“代码味道”,它是提示代码中某个地方存在错误的一个暗示,开发人员可以通过这种 smell(异味)在代码中追捕到问题。】

在我对重构的研究中,我看到一些模式(异味)一再出现。 这些都不是特别新鲜的事情,并且有很多书籍博客视频也对“代码异味”进行了介绍,也说明了如何处理它们,但我想展示一些具体的,特别的示例,当然,IntelliJ IDEA 也许能够(也可能不会)帮助你。

我试图解决的第一个问题是使用 null,特别是当它在代码周围散布 null 检查时。

亚林瓜子
 翻译得不错哦!

我觉得 Java 8 的 Optional 应该会解决很多这样的问题。 我认为特别指出也许为 null 的类型,这样设计是为了让你明确在这样的情况下怎么做才是正确的。

然而,事情是从不会像他们看见的那样简单,我怀疑为什么在 IntelliJ IDEA 中没有“让项目可选化”的灵丹妙药。而这正是我,一位开发者,需要认真考虑应该怎么做的领域。

我是菜鸟我骄傲
 翻译得不错哦!

我们不得不接受这个事实,即 null 意味着很多事情。 这可能意味着:

  1. 数值没有被初始化 (不管是偶然还是故意的)

  2. 数值无效

  3. 无用数值

  4. 该数值不存在

  5. 发生一些严重的错误,应该存在的东西却没有在哪里

  6. …可能还有很多其他的事情

如果你是一个具有明确设计目标而且编码规范严格的团队,你可以认为其中一部分不会在你的代码库中呈现 - 例如,在构造函数中始终初始化不变的字段,在实例化之前使用生成器或工厂来验证正确的组合 ,而不是在应用程序的核心使用 null(即将所有检查都放到一边)等等。

Tony
 翻译得不错哦!

Optional 仅解决了其中一种情况,案例 4. 例如,你向数据库查询一个指定 ID 的客户。之前,你可能已经使用 null 来表示这一点,但这可能是模棱两可的 - 这是否意味着没有找到客户? 还是有一个客户的 ID 但是这个 ID 并没有值? 或者是由于与数据库的连接失败而返回 null? 通过返回一个空的Optional,你已经消除了歧义 - 没有使用这个 ID 的客户。

在一个正常的,成熟的代码库中,会有许多人参与其中,这是否有可能告诉我们所有的null是什么意思,以及如何处理它们呢? 我们应该能通过一些小小的尝试来取得一些进展。

Tony
 翻译得不错哦!

案例研究

我正在使用 Morphia 项目作为文章中的一个例子,就像我在之前的谈话和关于重构的文章一样。 这是一个很好的示例项目,因为它是一个开源的且足够小,可以轻松下载和浏览,并且足够成熟,下面示例可能包含您在自己的应用程序中的实现代码。

异味:返回 null

我在路径中做了一个找到所有显式返回 null 的地方。我有一个理论,也许我们可以将这些方法改成返回一个 Optional


“返回 null”的“查找路径”结果

亚林瓜子
 翻译得不错哦!

示例 1: Converter.decode()

鉴于许多这些 *Converter 类似乎在 decode 方法中返回一个空值,所以我们可能希望这里更改 Converter 超类(一个名为 TypeConverter 的抽象类)以返回 Optional,这似乎是合理的。但是仔细看看代码实际所发生的情况:我们看到完全相同的模式一再发生 - 该方法检查传入的值是否为空,如果有,返回null:

@Override
public Object decode(final Class targetClass, final Object fromDBObject, final MappedField optionalExtraInfo) {
    if (fromDBObject == null) {
        return null;
    }
    //...now do the decoding...
}

第一个问题是 fromDBObject 实际上可以为 null 吗?代码是非常复杂的,所以很难说,但从理论上看,似乎是合理的,因为这是数据库中的一个值。

一个快速的搜索显示,这个方法的所有实例实际上只是从一个中心位置调用,所以不用在 21 个不同的地方进行这个检查,所以我们可以在一个地方做,而从那里假定 fromDBObject 不能再为null 。

亚林瓜子
 翻译得不错哦!

解决方案: @NotNull 参数

我原来的假设,我们这里可以使用 Optional 证明是错误的。相反,我要更改 decode 的方法签名来声明 fromDBObject 不能为 null - 我选择使用 JetBrains 注释来执行此操作。

public abstract T decode(Class<T> targetClass,
                         @NotNull Object fromDBObject,
                         MappedField optionalExtraInfo);

然后我移动 null 检查(和后续的空返回),其中 fromDBObject 实际上可以为 null,调用一个叫 decode 的方法。


将 null 检查移动到单个调用方法点,其中 fromDBObject 可为 null。

它使得调用方法更加不整洁,但将该逻辑限制在单个位置,而不是分散在所有实现中。现在,我们可以记录一个事实,即 fromDBObject 不会为 null,或者依靠注释来为我们做这个事情,所以我们不必在 Converter 实现中执行这个 null 检查。

亚林瓜子
 翻译得不错哦!

接下来我们整理并删除所有重复的代码,这一点 IntelliJ IDEA 会帮我们完成。如果我们回到 TypeConverter 中含有注解为 @NotNull 参数的抽象方法,会得到一个警告:

警告实现中没有注解这个参数

我们在这个警告上使用 Alt+Enter,快速修复建议可以让我们对这个方法的所有实现应用注解,做起来很容易,只管去做。

使用快速修复应用到所有实现

我们的 VCS 日志显示所有 Converter 实现都有变化

这里为 decode 方法的参数添加了 @NotNull 注解,但是我们仍然没找到并删除所有重复的空检查代码。好消息是我们说过 fromDBObject 不会是 null,我们可以使用 inspection(检查) 来查找所有多余的空检查代码并删除它们。

边城
 翻译得不错哦!

其中一个办法是进入一个我们知道已经存在检查的实现(这里我选择了 StringConverter) 来查看 IntelliJ IDEA 给出来的警告。

值不可能为 null 时不需要空检查

这是由“恒定条件&异常”检查触发的。我们可以在这段代码上运行此检查,以便轻松找到其它示例,因此使用 Ctrl+Shift+Alt+I 并输入检查名称

使用 Ctrl+Shift+Alt+I 按名称运行检查

这会返回更多的结果,通过按目录对结果进行分组,我可以轻松看到所有 Converter 实现。

我可以使用右边的预览窗口来查看哪些代码被标记出来,并看到 IntelliJ IDEA 建议怎么处理每个问题。通看一遍并确认这是我在查找的空检查之后,我选择 converters 目录并按下“Simplify boolean expression(简化布尔表达式)”按钮。

我会进入 VCS 本地变动窗口检查变化,并使用 Show Diff (比较查看,Ctrl+D) 来检查应用于 36 个文件的变更。

使用比较视图来检查变更

边城
 翻译得不错哦!

只要我愿意,我甚至可以在比较视图进行一些简单的编辑 —— 我会使用 Ctrl+Y 删除不需要的空行,即文件(右侧的文件)中的 26 和 27 行。使用 Alt+Right 可以检查所有存在变化的文件,我找到一个空检查未被删除的示例(这是一个测试用的 Converter,没有放在 converters 目录下),不过我甚至可以在比较视图使用快速修复来删除它。

这个智能检查让我放心使用 IntelliJ IDEA 的自动更改功能,也让我进行了一些其它调整。最后要做的就是运行所有测试,它们都通过的时候(哇哦!)就是提交这些改变最好的时机。

如果在文档中添加关于参数不能为 null,并且 IDE 会在你传入 null 值的时候产生警告,这样做会让你觉得不爽,你可以在提交代码之前删除 @NotNull —— 毕竟它的使命已经完成。这样的话,你最后应该更新 Javadoc(文档) 说明假设该参数不为 null。

边城
 翻译得不错哦!
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们
评论(0)
Ctrl/CMD+Enter

暂无网友评论
顶部