Java:何时跳过对象的空检查?

时间:2017-07-26 20:23:31

标签: java object nullpointerexception null

我在Java代码中使用了很多防御性空检查。尽管他们很好地服务于他们的目的(大部分时间),但是他们会以“难看”的代码进行巨大的交易。

将这些空检查始终放入是否真的有意义?例如:

if(object == null){
  log.error("...")
  throw new SomeRuntimeException("");
} else{
  object.someMethod();
}

实际上,上面的代码等同于语句object.someMethod();

如果object的值为null,则在两种情况下都会抛出异常(后面的NullpointerException)。

屏蔽NullpointerExcetion(NPE)并抛出一些自定义的RunTimeException(如上面的代码段)真的有意义吗? 我观察到一些开发人员将NPE视为邪恶,经常试图找出掩盖它的防御方法并用一些自定义异常掩盖它。 这种掩蔽真的需要吗?

问题

  1. 如果我们无法从该null状态恢复,那么允许我们的代码通过NPE失败是否有意义? (在上面的例子中,它似乎是一个不可恢复的场景。)
  2. 如果没有,为什么?

4 个答案:

答案 0 :(得分:8)

在您发布的情况下,支票没有任何好处。您将一个RuntimeException替换为另一个RuntimeException,它没有额外的信息或价值(并且对于那些不熟悉您的代码的人来说可能有点 ,因为每个人都知道什么是NPE是,并不是每个人都知道你的SomeRuntimeException是什么。)

主要两次我考虑进行明确检查:

  1. 当我想抛出已检查的异常而不是未选中时。
  2. 当我想在实际使用引用之前检查null时。
  3. 第二种情况尤其重要,因为我只是为了以后存储引用:例如,在构造函数中。在这种情况下,当有人使用引用并触发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();