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)
...
}
我在 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)
...
}