7

我在 github 上有一个由codacy分析的项目。分析建议对以下代码行“避免使用 null” :

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

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

4

5 回答 5

6

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

require(Option(path).isDefined, "Must have a real Path")
于 2017-04-17T08:39:01.517 回答
6

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

于 2017-04-17T09:12:51.483 回答
4

最惯用的方法是避免 require (不确定,但我认为它可以引发异常 - Scala 强烈建议反对)

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

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

注意:处理 null 情况的最佳位置可能是在您的函数内部。在这种情况下,您应该执行类似的操作

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

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

于 2017-04-17T08:58:37.260 回答
2

无需显式检查 null 或包装 pathOption. 你可以这样做:

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

这将返回 a Option,这可能不是您想要的,但在这种情况下,不是产生 a None,而是引发异常。require无论如何都会在你的例子中引发一个异常,所以如果这是你的调用者所期望的,那就明确地去做。

于 2017-04-17T14:07:42.093 回答
0

问题

禁止不使用 null 是最佳实践。这篇文章解释了为什么Guava : Ad-hoc Error Handling, Ambiguous Semantic, Slow Failing 等等。

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

理想的解决方案

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

中间解决方案

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

使用@NotNull/@Nullable 注解

由于没有语言/编译器级别的默认行为,因此库之间的阻抗不匹配。

实用解决方案

用 Predef2 用最少的样板逻辑定义我自己的类。我仍然只会得到一个“避免使用 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)
    ...
}
于 2017-05-01T16:56:14.227 回答