Java Integer compareTo() - зачем использовать сравнение или вычитание?

Я обнаружил, что реализация java.lang.Integer метода compareTo выглядит следующим образом:

public int compareTo(Integer anotherInteger) {
    int thisVal = this.value;
    int anotherVal = anotherInteger.value;
    return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
}

Вопрос в том, почему вместо вычитания используйте сравнение:

return thisVal - anotherVal;

Ответ 1

Это связано с переполнением целых чисел. Когда thisVal очень велико, а anotherVal отрицательно, то вычитание последнего из первого дает результат, превышающий thisVal, который может переполняться в отрицательный диапазон.

Ответ 2

Вычитается "трюк" для сравнения двух числовых значений!

        int a = -2000000000;
        int b =  2000000000;
        System.out.println(a - b);
        // prints "294967296"

Здесь a < b, но a - b положителен.

НЕ ИСПОЛЬЗУЙТЕ эту идиому. Это не работает.

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

См. также

  • Java Puzzlers Головоломка 65: Странная сага о подозрительной сортировке

    В этой головоломке есть несколько уроков. Наиболее характерным является: Не используйте компаратор с вычитанием, если вы не уверены, что разница между значениями никогда не будет больше Integer.MAX_VALUE. В более общем плане, остерегайтесь переполнения int. Еще один урок состоит в том, что вам следует избегать "умного" кода. Стремитесь писать четкий, правильный код и не оптимизировать его, если это не доказывает необходимость.

Ответ 3

Проще говоря, тип int недостаточно велик, чтобы сохранить разницу между двумя произвольными значениями int. Например, разница между 1,5 миллиардами и -1,5 миллиардами составляет 3,0 миллиарда, но int не может содержать значения, превышающие 2,1 миллиарда.

Ответ 4

Возможно, чтобы избежать переполнения/недогрузки.

Ответ 5

В дополнение к проблеме переполнения следует заметить, что версия с подстановкой не дает одинаковых результатов.

  • Первая версия compareTo возвращает одно из трех возможных значений: -1, 0 или 1.
  • Если вы замените последнюю строку на вычитание, результатом может быть любое целочисленное значение.

Если вы знаете, что переполнения не будет, вы можете использовать что-то вроде этого:

public int compareTo(Integer anotherInteger) {
    return sign(this.value - anotherInteger.valuel);
}