Я удивлен, что это даже сработало однажды. Вот то, что я думаю, будет хорошо работать:
codeMed.setComparator(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return (o1 != null ? o1 : Integer.MAX_VALUE) - (o2 != null ? o2 : Integer.MAX_VALUE);
}
});
Это предполагает, что любое значение null
обрабатывается так, как если бы оно представляло наибольшее возможное значение int
. Это заставит его переместиться в конец списка в возрастающем отсортированном столбце или вверху, если он находится в убывающем отсортированном столбце. Если необходимо обратное, переключите Integer.MAX_VALUE
на Integer.MIN_VALUE
.
То, что вы сделали, не работает, потому что вы нарушили это:
Разработчик должен убедиться, что sgn (сравнить (x, y)) == -sgn (сравнить (y,
x)) для всех x и y. (это подразумевает, что сравнение (x, y) должно бросить
исключение тогда и только тогда, когда сравнение (y, x) вызывает исключение.)
Примером такого нарушения является случай, когда o1
равен 5
, а o2
равен null
. В этом случае compare(o1, o2)
возвращает -1
и compare(o2, o1)
возвращает -1
. Один из них должен возвращать положительное значение, а другой - отрицательное, либо оба должны возвращать 0
.
Обновление
Это то, что вам нужно.
public class Model {
private final ObjectProperty<Integer> v = new SimpleObjectProperty<>();
public Model(Integer v) {
this.v.setValue(v);
}
public final ObjectProperty<Integer> vProperty() {
return this.v;
}
public final Integer getV() {
return this.vProperty().get();
}
public final void setV(final Integer v) {
this.vProperty().set(v);
}
}
ObservableList<Model> list = FXCollections.observableArrayList();
list.addAll(new Model(20), new Model(-30), new Model(null), new Model(10));
TableView<Model> tv = new TableView<>();
TableColumn<Model, Integer> tc = new TableColumn<>();
tc.setCellValueFactory(new PropertyValueFactory<>("v"));
tv.getColumns().add(tc);
tv.setItems(list);
Comparator<Integer> ascComparator = (o1, o2) ->
(o1 != null ? o1 : Integer.MAX_VALUE) -
(o2 != null ? o2 : Integer.MAX_VALUE);
Comparator<Integer> descComparator = (o1, o2) ->
(o1 != null ? o1 : Integer.MIN_VALUE) -
(o2 != null ? o2 : Integer.MIN_VALUE);
@SuppressWarnings("unchecked")
Comparator<Integer> defaultComparator = TableColumn.DEFAULT_COMPARATOR;
tc.comparatorProperty().bind(
Bindings.when(tc.sortTypeProperty().isEqualTo(SortType.ASCENDING))
.then(ascComparator)
.otherwise(
Bindings.when(tc.sortTypeProperty().isEqualTo(SortType.DESCENDING))
.then(descComparator)
.otherwise(defaultComparator)));
Кроме того, я хотел бы отметить, что, хотя использование Integer.MIN_VALUE
и Integer.MAX_VALUE
должно работать большую часть времени, существует гораздо более высокий риск возникновения проблем целочисленного и переполнения, но я не уверен, что это проблема использования компараторов и сопоставимых объектов.
Если вы хотите быть более безопасным, сделайте кучу if-else:
Comparator<Integer> ascComparator = (o1, o2) -> {
if (o1 == null && o2 == null) return 0;
else if (o1 == null && o2 != null) return -1;
else if (o1 != null && o2 == null) return 1;
else return Integer.compare(o1, o2);
};
Обновите снова
Посмотрев на то, что вы пытались, я понял, что это работает:
Comparator<Integer> comparator = (o1, o2) -> {
final boolean isDesc = tc.getSortType() == SortType.DESCENDING;
if (o1 == null && o2 == null) return 0;
else if (o1 == null && o2 != null) return isDesc ? -1 : 1;
else if (o1 != null && o2 == null) return isDesc ? 1 : -1;
else return Integer.compare(o1, o2);
};