Ваша нулевая обработка нарушает контракт compare
, так как вы считаете null
равным любому другому значению, в то время как JavaDoc пишет:
Сравнивает два аргумента для порядка. Возвращает отрицательное целое число, ноль или положительное целое число, поскольку первый аргумент меньше, равен или больше второго.
и, в частности:
Наконец, разработчик должен убедиться, что compare(x, y)==0
подразумевает, что sgn(compare(x, z))
== sgn(compare(y, z))
для всех z.
, который ваш код не может выполнить для x = null
, y = "a"
, z = "b"
.
Поэтому, если какие-либо объекты или свойства в списке имеют значение null
, список может быть отсортирован неправильно.
При этом интересно, может ли список действительно содержать null
значений или свойств? Если нет, я бы удалил все проверки null
и в итоге получил бы
Collections.sort(list, new Comparator<TestObject>() {
@Override public int compare(TestObject o1, TestObject o2) {
int c = o1.getTaxIdNumber().compareTo(o2.getTaxIdNumber);
if (c != 0) {
return c;
}
return o1.getProviderName().compareTo(o2.getProviderName());
}
}
Если список может содержать null
объектов или свойств, вы должны определить, являются ли значения null
первыми или последними, и соответственно расширить компаратор:
Collections.sort(list, new Comparator<TestObject>() {
@Override public int compare(TestObject o1, TestObject o2) {
// insert null-checks for o1, o2 here
int c = cmp(getTaxIdNumber(), o2.getTaxIdNumber());
if (c != 0) {
return c;
}
return cmp(o1.getProviderName(), o2.getProviderName());
}
private <T extends Comparable<? super T>> cmp(T o1, T o2) {
if (o1 == o2) {
return 0;
else if (o1 == null) {
return -1;
} else if (o2 == null) {
return 1;
} else {
return o1.compareTo(o2);
}
}
}
Теперь это довольно много повторяющегося и хитрого кода, поэтому сотрудники Apache написали CompareToBuilder . С этим API вы можете просто написать:
@Override int compare(TestObject r1, TestObject r2) {
// insert null checks for r1 and r2 here - if you really need them
return new CompareToBuilder()
.append(r1.getTaxIdNumber(), r2.getTaxIdNumber())
.append(r1.getProviderName(), r2.getProviderName())
.toComparison();
}
}