用 XOR 取反布尔表达式

negation of boolean expressions with XOR

我有这个:

// returns true if both are equal (independent of scale) and also checks against null
public static boolean isEqual(BigDecimal val1, BigDecimal val2) {
        // 1. check: both will be null or both will be non-null.
        if (val1 != null ^ val2 != null) return false;
        // 2. check: if not null, then compare if both are equal
        return !(val2 != null && val1.compareTo(val2) != 0);
    }

我想将布尔表达式合并为一个。所以我用这个:

public static boolean isEqual(BigDecimal val1, BigDecimal val2) {
    return !(val1 != null ^ val2 != null) && !(val2 != null && val1.compareTo(val2) != 0);
}

但是,我担心这是否正确。这个对吗?这会是 simplified/shorten 吗?

在答案的帮助下,缩短的解决方案是:

// returns true, if both are null or both are equal 
// (independent of their numbers scales)
public static boolean isEqual(BigDecimal val1, BigDecimal val2) {
    return val1 == null ? val2 == null : val2 != null && val1.compareTo(val2) == 0;
}

您可以使用 Comparator.nullsFirst (or Comparator.nullsLast):

public static boolean isEqual(BigDecimal val1, BigDecimal val2) {
    return Comparator.nullsFirst(BigDecimal::compareTo).compare(val1, val2) == 0;
}

示例:

    System.out.println(isEqual(null, null));
    System.out.println(isEqual(null, new BigDecimal(1.0)));
    System.out.println(isEqual(new BigDecimal(1.0), null));
    System.out.println(isEqual(new BigDecimal(1.0), new BigDecimal(1.0)));

输出

true
false
false
true

使用 ^ 作为逻辑 XOR 运算符是非常不寻常的。它有效,但为了可读性,我会避免使用它。 != 是一个很好的替代品。

return !((val1 != null) != (val2 != null)) && !(val2 != null && val1.compareTo(val2) != 0);

现在你可以用==代替双重否定。不错

return ((val1 != null) == (val2 != null)) && !(val2 != null && val1.compareTo(val2) != 0);

您还可以通过 De Morgan's laws:

分发剩余的 !
return ((val1 != null) == (val2 != null)) && (val2 == null || val1.compareTo(val2) == 0);

好多了,但老实说我还是觉得不方便。即使不是单行语句,我也会选择更直接的东西:

if (val1 == null) {
    return val2 == null;
}
else {
    return val2 != null && val1.compareTo(val2) == 0;
}

您可以使用三元运算符代替 if/else。根据个人喜好,您会发现更具可读性:

return val1 == null
    ? val2 == null
    : val2 != null && val1.compareTo(val2) == 0;

您提到您需要使用 compareTo()。对于可能阅读此答案的其他人,如果您不必使用 compareTo(),我会改用 equals()

if (val1 == null) {
    return val2 == null;
}
else {
    return val1.equals(val2);
}

那么,碰巧的是,您甚至根本不需要编写此方法。内置的 Objects.equals() 方法正是这样做的:如果两个对象相等,或者它们都为空,则 returns 为真。

如果规模不是问题,我会在这里使用三元,并利用 Object#equalsnull 返回 false:

//Basically Objects#equals at this point
public static boolean isEqual(BigDecimal val1, BigDecimal val2) {
    return val1 == null ? val2 == null : val1.equals(val2);
}

因此在每种情况下:

[1: null, 2: null]: true
[1: null, 2:  num]: false
[1: num,  2: null]: false
[1: num,  2:  num]: Object#equals

然而,正如您所指出的,您也想在不考虑缩放比例的情况下进行比较。所以我们必须包括另一个空检查,因为如果你通过 null:

#compareTo 抛出 NPE
public static boolean isEqual(BigDecimal val1, BigDecimal val2) {
    return val1 == null
            ? val2 == null
            : val2 != null && val1.compareTo(val2) == 0;
}

因此在每种情况下(再次):

[1: null, 2: null]: true
[1: null, 2:  num]: false
[1: num,  2: null]: false
[1: num,  2:  num]: BigDecimal#compareTo

我会发现它更具可读性,但它仍然有点笨拙。在这一点上,一个写得很好且简洁的评论(或者,根据其他答案分行)可能比重写代码对你更好。