我在 github 上有一个由codacy分析的项目。分析建议对以下代码行“避免使用 null” :
def doSomethingWithPath(path:Path) = {
require(path != null, "Path should not be null") //<-to avoid
...
}
修复它的最简单的scala惯用方法是什么?
我在 github 上有一个由codacy分析的项目。分析建议对以下代码行“避免使用 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")
我会保持原样。你在这里并没有真正使用 null ,只是为了防止它。另一种方法可能是完全删除该行,并决定根本不处理 null。在构建良好的代码库中忽略 null 的可能性可能很好,无论如何它都不应该出现,并且 null 将是一个错误,但是一个简单的保护措施可以防止出现更微妙的错误,以防出现问题和null 实际上发生了。
最惯用的方法是避免 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 的答案也是我的选择
无需显式检查 null 或包装 path
在Option
. 你可以这样做:
path match {
case p: String => Option(doSomethingWith(p))
case _ => None //if path is null this will be returned
}
这将返回 a Option
,这可能不是您想要的,但在这种情况下,不是产生 a None
,而是引发异常。require
无论如何都会在你的例子中引发一个异常,所以如果这是你的调用者所期望的,那就明确地去做。
禁止不使用 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 都可能被视为编译错误。我不知道这是否完全可行。
由于没有语言/编译器级别的默认行为,因此库之间的阻抗不匹配。
用 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)
...
}