Scala 避免使用 null

Scala avoid using null

我在 github 上有一个项目,由 codacy 分析。分析建议"Avoid using null"下面一行代码:

def doSomethingWithPath(path:Path) = {
    require(path != null, "Path should not be null") //<-to avoid
    ...
}

修复它的最简单的 Scala 惯用方法是什么?

如果path实际上可能 null这可能是最简单的。

require(Option(path).isDefined, "Must have a real Path")

最惯用的方法是避免 require(不确定,但我认为它会抛出异常——Scala 强烈建议不要这样做)

def doSomethingWithPath(path:Path): Option[stuff] = { // will return an option of the type you were returning previously.
     Option(path).map { notNullPath =>
       ...
     }
}

现在可能的 null 情况将返回给调用者,can/will 传播返回的 Option 直到知道如何正确处理它的层。

Note: it is possible that the best place to handle the null case is inside you function. In that case you should do something like

Option(path).map { notNullPath =>
    ...
}.getOrElse(/* take care of null case */)

如果您确实想保留 require,那么 也是我的选择

我会保持原样。您实际上并没有在这里使用 null ,只是为了防止它。另一种方法是完全删除该行,并决定根本不处理空值。在构建良好的代码库中忽略 null 的可能性可能很好,无论如何它都不应该出现并且 null 将是一个错误,但是一个简单的守卫来捕获它可以防止出现更细微的错误,以防出现问题并且null 实际上发生了。

无需显式检查 null 或将 path 包装在 Option 中。 你可以这样做:

 path match {
  case p: String => Option(doSomethingWith(p))
  case _         => None //if path is null this will be returned
 }

这将 return 一个 Option,这可能不是你想要的,但在那种情况下,不是生成 None,而是引发一个异常。 require 无论如何都会在您的示例中引发异常,所以如果这是您的调用者所期望的,请明确地执行它。

问题

禁止使用 null 是最佳做法。 This article explains why and Guava:临时错误处理、歧义语义、缓慢失败等。

编写 require 是因为在不满足调用方法的先决条件时需要快速和干净地失败。问题是,正如@puhlen 解释的那样,它只用另一个异常(尽管更具描述性)替换了 NPE。

理想的解决方案

在理想世界中,path:Path 将与 number:Int 相同,并且不需要对对象的存在进行测试。问题是 scala(和其他语言一样)允许 null 破坏纯面向对象的方法。

中间解决方案

java/scala 编译器应该强制将 Optional 类型作为管理 null 的唯一代码,并强制在类型系统中存在 null。在这种情况下,对 null 的任何使用都可能被视为编译错误。我不知道这是否完全可行。

使用@NotNull/@Nullable 注释

由于没有 language/compiler 级默认行为,库之间的阻抗不匹配。

实用解决方案

使用具有最少样板逻辑的 Predef2 定义我自己的 class。我仍然只会得到一个 "Avoid using null" 或使用 guava Preconditions.checkNotNull

object Predef2{
    def requireNotNull(object:AnyRef) = 
       require(path != null, "Some object should not be null")
}
def doSomethingWithPath(path:Path) = {
    requireNotNull(path)
    ...
}