Pull to refresh

Comments 16

Согласно документации использование Comparable возможно, если для сравнения используется естественный порядок (class's natural ordering).


Документация (SE 8):
public interface ComparableThis interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.


А можете пальцем показать, где вы тут нашли «возможно, если»? Вот тут не так написано. Тот порядок, который задается Comparable, называется естественным. Если вам такой порядок нужен — используйте a.compareTo(B). Если нет — пишете компаратор.
Согласен, недостаточно внимательно прочитал. Получается, документация дает определение: «естественный порядок» это порядок, заданный в Comparable.
Однако это не дает формальных правил чтобы разработчик смог понять, может он он в своем классе имплементировать Comparable или нет.
Ну я бы так сказал — если у вас есть естественный порядок (он всегда один) — то вам подойдет Comparable. Ну то есть, понятно как сортировать даты, строки, числа — у них у всех есть его реализация. Но если вы хотите сортировать строки без учета больших и маленьких букв — то компаратор наше все.

для меня использование .compareTo омрачается необходимостью проверки на NULL каждый раз.
с java знаком шапочно, может быть я что-то не так понимаю.

Обычно в пользовательском коде не требуется явно вызвать .compareTo, это делают за нас сортировщики у коллекций, стримов и прочего. И уже для них специфицируется возможность работы с nullable значениями, а она нужна не только для сравнения. Так что необходимость проверки на null при сортировке обычно не является проблемой.
Также в этой статье я не затрагивал проблему total order, когда compareTo возвращает 0. Так как она одинаковая для обоих интерфейсов сравнения.
Обычно в пользовательском коде не требуется явно вызвать .compareTo, это делают за нас сортировщики у коллекций, стримов и прочего.

хорошо, а как тогда сравнивать «в пользовательском коде»?


private void someMethod(BigDecimal b) {
    if ( b.compareTo(BigDecimal.ZERO) <= 0 ) {
        // value must be positive, abort
    }
    // do something
}

приходится или вставлять проверку на NULL (что загрязняет код), или «переворачивать» условие (что опять же плохо читается), или писать отдельную функцию-компаратор.


P. S. впрочем, понятно, что тут дело не в compareTo, а в обработке NULL в java. может быть оно сделано правильно, но мне «не зашло» )

Если хотите вызывать любой метод объекта по ссылке first, в т.ч. first.compareTo(second), и эта ссылка может содержать значение null, то нужно обрабатывать случаи first = null и first != null как это делаете Вы.
Более того, если second может содержать null, тогда или перед вызовом метода compareTo(), или внутри него, нужно предусмотреть обработку случаев с second = null и second != null.
Можно также написать компаратор, который обрабатывает оба значения как nullable. В целом это не проблема сравнения, это проблема обработки nullable ссылок.
Было бы интересно посмотреть контекст, в котором Вы используете этот метод. Если его приходится дергать руками, то есть ли смысл вообще делать свой класс реализацией Comparable?

речь в данном случае не про свой класс, а про BigDecimal (ну и не только, но сравнений BigDecimal в коде много и выглядит на мой взгляд это «так себе»).


да, мой комментарий не имеет отношения к статье )


В целом это не проблема сравнения, это проблема обработки nullable ссылок.

это понятно. непонятно как писать красиво.

Я ошибочно обобщил Ваш вопрос и даже пример кода. Поискал по текущему рабочему проекту использования compareTo, и понял что оно действительно активно используется при работе с BigDecimal.
В целом подход проверки на null остается тот же. Если везде логика обработки разная, то придется в каждом месте проверять условие. Если логику можно сделать одинаковой в разных местах, то следует вынести ее в отдельный метод. Реализовать этот метод в виде утилитного в текущем классе с бизнес логикой, или же в виде компаратора — дело вкуса.
или «переворачивать» условие (что опять же плохо читается), или писать отдельную функцию-компаратор

Если посмотреть в код компаратора BigDecimal, можно увидеть, что переворот условия не сработает.

Иногда программистам очень неудобно работать с ссылками на null. Например, вы сравниваете две строки. Если обе переменные не null, тогда можно просто вызвать s1.equals(s2), и все будет работать. А вот если s1 может быть null, придется писать код, который учитывает эту ситуацию, чтобы не возникло NullPointerException.

Поэтому программисты придумали служебный класс Optional<T>.

Один объект Optional всегда можно сравнить с другим объектом Optional через метод equals, даже если они хранят в себе ссылки на null.

Грубо говоря, класс Optional позволяет «более красиво» записывать проверки на null и действия в случае, если внутри объект Optional хранится null.

Э-э-э, ну и что тут сложного-то, в написании equals(s1, s2)?

А что скажите про thenComparing у компараторов?
Я это к чему? При казалось бы похожей сфере применимости, у Comparator и Comparable, все-таки есть случаи, когда их возможности расходятся. Именно поэтому существуют различные языковые конструкции.

Мне кажется этот вопрос больше относится к наличию утилитных методов для удобной реализации сравнения. С 1.8 такие методы есть для chaining-а компараторов, с 1.7 есть методы вроде статического Integer#compare(x,y)
Вы пишите, что для реализации Comparator надо создавать отдельный класс, а для Comparable якобы не надо.
И то и другое являются интерфейсами разных пакетов. И одно и второе может имплементить в один и тот же класс.
Данная статья хорошо подходит джунам, но для джунов надо сначала разжевать, что такое Comparator, потом Comparable, привести пример с созданием классов и имплементации. И выкинуть
неявно: Arrays.sort(accountsList)
явно: Arrays.sort(accountsList, accountByValueComparator)

и статья станет не плохой. Доработайте, пожалуйста)

Могли бы Вы уточнить?
Технически можно сделать чтобы класс имплементировал для самого себя интерфейс компаратора (или валидатора, сериализатора). На практике это явное слияние зон ответственности, и вряд ли будет использоваться. Вопрос в том чтобы убрать слово «отдельный»?
Как без использования примеров явно/неявно подвести к проблеме поиска использований определенного метода compareTo?
Sign up to leave a comment.

Articles

Change theme settings