Почему мой простой компаратор сломан?
Вопрос
У меня есть класс, который я упростил до этого:
final class Thing {
private final int value;
public Thing(int value) {
this.value = value;
}
public int getValue() {
return value;
}
@Override public String toString() {
return Integer.toString(value);
}
}
Я хочу отсортировать массив этой вещи.Итак, я создал простой копмаратор:
private static final Comparator<Thing> reverse = new Comparator<Thing>() {
public int compare(Thing a, Thing b) {
return a.getValue() - b.getValue();
}
};
Затем я использую форму с двумя аргументами Arrays.sort
.
Это отлично работает для моих тестовых случаев, но иногда все идет наперекосяк, когда массив заканчивается в странном, но повторяемом порядке.Как это может быть?
Решение
Переполнение целых чисел... или, точнее, недостаточный поток.
Вместо этого выполните явное сравнение:
private static final Comparator<Thing> reverse = new Comparator<Thing>() {
public int compare(Thing a, Thing b) {
int av = a.getValue(), bv = b.getValue();
return (av == bv) ? 0 : ((av < bv) ? -1 : +1);
}
};
Использование вычитания подойдет, если вы уверены, что разница не будет "оборачиваться".Например, когда значения, о которых идет речь, должны быть неотрицательными.
Другие советы
Вы не можете использовать минус для создания сравнения.Вы переполнитесь, когда абсолютная разница превысит Integer.MAX_VALUE
.
Вместо этого используйте этот алгоритм:
int compareInts( int x, int y ) {
if ( x < y ) return -1;
if ( x > y ) return 1;
return 0;
}
Мне хотелось бы иметь эту функцию в библиотеке для таких целей.
попробуй
System.out.println(Integer.MAX_Value - Integer.MIN_VALUE);
Это должно возвращать положительное число как MAX_VALUE > MIN_VALUE, но вместо этого выводит значение -1
При сравнении примитивов Java желательно преобразовать их в их объектные аналоги и полагаться на их compareTo()
методы.
В этом случае вы можете сделать:
return Integer.valueOf(a.getValue()).compareTo(b.getValue())
Если вы сомневаетесь, используйте хорошо протестированную библиотеку.
Какие цифры вы туда вбрасываете?Если ваши числа достаточно велики, вы могли бы использовать МИНИМАЛЬНЫЕ / максимальные значения для целых чисел и в итоге получить беспорядок.
Если значение a очень отрицательное, а значение b очень положительное, ваш ответ будет очень неправильным.
IIRC, Int overflow бесшумно оборачивается в JVM
-- МаркусК