Я нашел это 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;
Это связано с целочисленным переполнением. Когда thisVal
очень велико, а anotherVal
отрицательно, то вычитание последнего из первого дает результат больше, чем thisVal
, который может выходить за пределы диапазона отрицательных значений.
Проще говоря, тип int
недостаточно велик для хранения разницы между двумя произвольными значениями int
. Например, разница между 1,5 миллиардами и -1,5 миллиардами составляет 3,0 миллиарда, но int
не может содержать значения больше 2,1 миллиарда.
Уловка с вычитанием для сравнения двух числовых значений не работает !!!
int a = -2000000000;
int b = 2000000000;
System.out.println(a - b);
// prints "294967296"
Здесь a , но
a - b
положительно.
НЕ используйте эту идиому. Не работает.
Более того, , даже если он работает , он НЕ обеспечивает какое-либо существенное улучшение производительности и может фактически стоить читабельности.
У этой головоломки есть несколько уроков. Наиболее конкретный из них: Не используйте компаратор на основе вычитания, если вы не уверены, что разница между значениями никогда не будет больше, чем
Integer.MAX_VALUE
. В общем, остерегайтесь переполненияint
. Еще один урок состоит в том, что вам следует избегать «умного» кода. Стремитесь писать ясный, правильный код и не оптимизируйте его, если это не окажется необходимым.
Возможно, чтобы избежать переполнения / потери значимости.
Помимо проблемы с переполнением, вы должны заметить, что версия с вычитанием не дает таких же результатов .
Если вы знаете, что переполнения не будет, вы можете использовать что-то вроде этого:
public int compareTo(Integer anotherInteger) {
return sign(this.value - anotherInteger.valuel);
}