我正在审查我认为值得怀疑的最佳实践和推荐编码 java 手册。
推荐:
String variable;
"xx".equals(variable) // OK
variable.equals("xx") //Not recomended
因为防止出现不受控制的 NullPointerException
这是真的?
这是一种非常常见的技术,如果变量为 null 而不是抛出一个NullPointerException
. 但我想我会有所不同,并说我不会将此视为您应该始终遵循的建议。
但:
NullPointerException
不一定是最坏的结果。假装一切都好,直到它最终失败,这并不是一个更好的选择。快速失败是好事。就我个人而言,我不认为在所有情况下都需要使用这种技术。我认为应该由程序员根据具体情况来判断。重要的是确保您以适当的方式处理了 null 案例,并且您如何处理取决于具体情况。检查空值的正确处理可能是测试/代码审查指南的一部分。
是真的。如果variable
在null
您的示例中,
variable.equals("xx");
将抛出 NPE,因为您不能equals
在空对象上调用方法 ()。但
"xx".equals(variable);
只会返回false
而不会出错。
实际上,我认为最初的建议是正确的。如果你使用variable.equals("xx")
,那么你会得到一个NullPointerException
ifvariable
为空。将常量字符串放在左侧可以避免这种可能性。
这种防御是否值得许多人认为是不自然的习语的痛苦取决于你。
这是 Java(和 C#)程序中使用的常用技术。第一种形式避免了空指针异常,因为该.equals()
方法是在常量 string 上调用的"xx"
,它永远不会为空。与 null 相比,非 null 字符串为 false。
如果您知道它variable
永远不会为空(并且您的程序在其他方面不正确,如果它曾经为空),那么使用variable.equals("xx")
就可以了。
确实,以这种方式使用对象的任何属性都可以帮助您避免 NPE。
但这就是为什么我们有例外来处理这类事情。
也许如果你使用 "xx".equals(variable) 你永远不会知道变量的值是 null 还是不等于 "xx"。IMO 最好知道您在变量中获得了一个空值,因此您可以重新签名它,而不仅仅是忽略它。
您对检查的顺序是正确的——如果变量为空,在字符串常量上调用 .equals 将阻止 NPE——但我不确定我是否认为这是个好主意;我个人称之为“slop”。
Slop 是指您没有检测到异常情况,但实际上会养成习惯以个人避免检测到它。在很长一段时间内将 null 作为字符串传递最终会导致错误,这些错误可能晦涩难懂。
slop 编码与“Fail fast fail hard”相反。
使用 null 作为字符串偶尔会产生一个很好的“特殊”值,但您尝试将其与某物进行比较这一事实表明您对系统的理解是不完整的(充其量)——您越早发现这个事实, 更好。
另一方面,默认情况下将所有变量设为最终变量、使用泛型并最小化所有对象/方法的可见性是减少浪费的习惯。
如果您需要检查null
,我发现这比
if (variable != null && variable.equals("xx"))
. 这更多的是个人喜好问题。
附带说明一下,这是一个设计模式,其中此代码推荐可能没有任何区别,因为 String (ie Optional<String>
) 永远不会为空,因为来自设计模式的 .isPresent() 调用:
Optional<String> gender = Optional.of("MALE");
if (gender.isPresent()) {
System.out.println("Value available.");
} else {
System.out.println("Value not available.");
}
gender.ifPresent(g -> System.out.println("Consumer: equals: " + g.equals("whatever")));