отрицание логических выражений с помощью XOR - PullRequest
7 голосов
/ 20 сентября 2019

У меня есть это:

// 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);
}

Однако, я беспокоюсь, если это правильно.Это верно?Может ли это быть упрощено / сокращено?

С помощью ответа укороченное правильное решение:

// 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;
}

Ответы [ 4 ]

8 голосов
/ 20 сентября 2019

Использование ^ в качестве логического оператора XOR весьма необычно.Это работает, но я бы избежал этого для удобства чтения.!= - хорошая замена.

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

Теперь вы можете заменить двойное отрицание на ==.Хорошо.

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

Вы также можете распределить оставшиеся ! через законы де Моргана :

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() делает именно это: он возвращает true, если два объекта равны или оба они равны нулю.

3 голосов
/ 20 сентября 2019

Вы можете использовать Comparator.nullsFirst (или 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
2 голосов
/ 20 сентября 2019

Если бы масштабирование не было проблемой, я бы использовал здесь троичную форму и использовал бы Object#equals, возвращая false для null:

//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

Однако, как вы заметили, вы хотите сравнивать независимо от масштабирования.Поэтому нам нужно будет включить еще одну нулевую проверку, когда #compareTo бросает NPE, если вы передаете null:

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

Я нашел бы это более читабельным, но это все еще немного непривлекательно.На этом этапе хорошо написанный и лаконичный комментарий (или разделение строки на другой ответ), вероятно, поможет вам лучше, чем переписывание кода.

1 голос
/ 21 сентября 2019
public static boolean isEqual(BigDecimal val1, BigDecimal val2) {
        return  !(val1 != null ^ val2 != null) && !(val2 != null && val1.compareTo(val2) != 0);
    }

Не бойтесь использовать Xor, хороший программист должен хорошо разбираться в цифровых системах.

enter image description here

https://www.baeldung.com/java-xor-operator

Здесь можно упростить

...
!(val2 != null && val1.compareTo(val2) != 0)
...
to
(val2 == null || val1.compareTo(val2) == 0)

enter image description here

...