我在Java代码中使用了很多防御性空检查。尽管他们很好地服务于他们的目的(大部分时间),但是他们会以“难看”的代码进行巨大的交易。
将这些空检查始终放入是否真的有意义?例如:
if(object == null){
log.error("...")
throw new SomeRuntimeException("");
} else{
object.someMethod();
}
实际上,上面的代码等同于语句object.someMethod();
如果object
的值为null,则在两种情况下都会抛出异常(后面的NullpointerException)。
屏蔽NullpointerExcetion(NPE)并抛出一些自定义的RunTimeException(如上面的代码段)真的有意义吗? 我观察到一些开发人员将NPE视为邪恶,经常试图找出掩盖它的防御方法并用一些自定义异常掩盖它。 这种掩蔽真的需要吗?
问题
答案 0 :(得分:8)
在您发布的情况下,支票没有任何好处。您将一个RuntimeException替换为另一个RuntimeException,它没有额外的信息或价值(并且对于那些不熟悉您的代码的人来说可能有点 ,因为每个人都知道什么是NPE是,并不是每个人都知道你的SomeRuntimeException是什么。)
主要两次我考虑进行明确检查:
第二种情况尤其重要,因为我只是为了以后存储引用:例如,在构造函数中。在这种情况下,当有人使用引用并触发NPE时,可能很难找到那个null的位置。通过在将其保存到字段之前检查它,您更有可能找到根本原因。事实上,这是一个足够普遍的模式,JDK甚至为它提供了requireNonNull
帮助。
如果你看一下很多成熟的,高信誉的项目,我想你会发现"只是使用它,如果它发生就让NPE发生"模式很常见。举一个例子,JDK' Collections.sort
的代码只是list.sort(null)
,其中list
是方法参数。如果它为null,那么该行将抛出一个NPE。
答案 1 :(得分:4)
对于内部代码,一堆空检查是没用的。如果你将null传递给一个不期望它的方法,那么让NPE失败是可以接受的,而不是试图防止错误。如果您的代码是从您无法控制的其他代码调用的,则可以在方法的开头声明(Objects.requireNonNull),或者提供一个声明传入null的结果的Javadoc。后一种方法在JDK代码库中普遍使用。
答案 2 :(得分:3)
NPE被认为是不好的,因为它们没有提供语义"对刚刚发生的问题。关于Java应用程序中的任何代码段都可能会抛出NPE。因此,当它发生时,你没有立即知道导致NPE的原因:缺少用户条目?编程错误?滥用外部依赖?
由于各种可能的原因,在上层抓住NPE处理问题是非常糟糕的做法
所以,当你有可能时,就像你给出的例子一样,当你编写代码时,你就知道当object == null时它意味着什么。因此,如果您选择抛出具有语义含义的异常,则可以在上层特别捕获它,并在功能上处理这种特殊情况。
关于样板if if(... == null)else ...,如果使用Java 8和Home Screen Actions
,可以避免使用它答案 3 :(得分:0)
我编写了一个个人类ArgumentChecker.java,其中包含许多常用的简单静态方法,用于异常检查,如checkPositive(double value),checkEquals(int v1,int v2),checkNonDecreasingOrder(int ... args),checkNonNull(对象obj),......等两个例子如下。
public static void checkAllEqualsTo(int theValue, int... values){
for (int i = 0; i < values.length; i++) { // StringUtils is also a personal simple class containing some wrapped methods
if (values[i] != theValue)
throw new IllegalStateException(NOT_ALL_EQUAL_EXCEPTION + "; values = " + StringUtils.toString(values, values.length) + ", theValue = " + theValue);
}
}
public static void checkAllEquals(int... values){
if (values.length == 0){
return;
}
checkAllEqualsTo(values[0], values);
}
这些方法是可重用的,对这些异常检查方法的方法调用也简洁易读。
对于这个问题,代码变为:
ArgumentCheck.checkNonNull(object);
object.someMethod();