为什么 findbugs 在此代码中抛出空指针取消引用?

Why is findbugs throwing a null pointer dereference in this code?

我 运行 通过 Sonarqube 在我们的代码中查找错误,并且我收到空指针取消引用的错误:

There is a branch of statement that, if executed, guarantees that a null value will be dereferenced.

错误的代码就是这样:

public static boolean isBigDecimalDifferent(BigDecimal x, BigDecimal y) {
        return (x != null || y != null)
                && ((x != null && y == null) || (x == null && y != null) || x.compareTo(y) != 0);   
}

我想知道这怎么可能。唯一可能出现 NPE 的地方是调用 x.compareTo(y) 时,但是如果 x=null 那么 Java 将永远不会分析该分支,对吗?

这是一个错误,还是我遗漏了一些有关 Java 分析此语句的方式的信息?


更新

感谢您的投入。我最终建议他们将其更改为:

if (x!=null && y != null)
    return x.compare(y);
else
    return x!=y;

我觉得更清楚一点。如果没有人同意更改,我将按照建议进行操作并忽略该问题,即使我宁愿避免那样做。

我会这样写那个方法:

public static boolean isBigDecimalDifferent(BigDecimal x, BigDecimal y) {
   if (x == null) throw new IllegalArgumentException("x cannot be null");
   if (y == null) throw new IllegalArgumentException("y cannot be null");
   return (x.compareTo(y) != 0);
}

我认为它更容易阅读。

如果你不想在异常中表达 pre-conditions 我会说这也更清楚:

public static boolean isBigDecimalDifferent(BigDecimal x, BigDecimal y) {
   if (x == null) return (y != null);
   if (y == null) return (x != null);
   return (x.compareTo(y) != 0);
}

FindBugs 的逻辑太复杂了,这里出错了。你是对的,你在该代码中防御了取消引用 null

我会简化它,以便 FindBugs 理解它,这样任何后续的人 reader 也可以轻松地弄清楚它在做什么:

public static boolean isBigDecimalDifferent(BigDecimal x, BigDecimal y) {
    if (x == null) {
        return y != null;
    }
    if (y == null) {
        return x != null;
    }
    return x.compareTo(y) != 0;
}

旁注:通常,您会有一种方法来检查 相等性 ,如果要检查不等性,请使用 !


您在评论中说:

Unfortunately, it is legacy code that I haven't authority to change (I do wish I could!)

那么你必须注意到 FindBugs 无法解决这个问题,并在你的 FindBugs 设置中将其设为例外 (described in this question's answers)。