Что должно возвращать int compareTo(), когда строка параметра равна нулю?

Говорят, что когда входной параметр равен null, compareTo() должен вызывать исключение NullPointerException. Тем не менее, я реализую класс, который должен сравнивать поля с типом String. Эти поля не обязательно должны быть обязательными. Интересно, в этом случае

1) Что я должен вернуть, когда ввод равен нулю? Должны ли любые ненулевые строки лексикографически больше или меньше нуля?

и

2) Если это считается плохой практикой, есть ли поддерживающие аргументы? Должен ли я заставить пользователя использовать пустые строки? Если используется пустая строка, не будет ли это путать случай, когда поле не применимо, и случай, когда поле пусто? И если нужно исключить исключение, то, кроме предупреждения пользователя в руководстве, что еще я могу сделать?

РЕДАКТОР: Я не могу четко выражать себя здесь, но в программе, которую я реализую, строки, которые могут быть пустыми, - это все поля или класс, который не должен быть нулевым. Другими словами, объекты compareTo() не могут быть нулевыми, просто их частные поля могут быть. Поэтому в этом случае я считаю, что если я правильно выполняю функцию compareTo(), это не будет нарушать переходное требование, поскольку классы с нулевыми полями будут считаться одинаковыми всегда. Правильно ли я интерпретирую это неправильно?

Спасибо всем за ответы!

Ответ 1

Да, нет проблем с разрешением null полей для экземпляра - просто убедитесь, что порядок сортировки определен. Самым естественным было бы поместить его до или после всех настоящих строк, но здесь вы можете сделать что угодно, просто делать это последовательно. (Например, вы можете отсортировать null как "null".)

Вот пример реализации для одного члена:

class Example implements Comparable<Example> {

   @Nullable
   private String member;

   // TODO: getter, setter, constructor, ...

   public int compareTo(Example that) {
      if(this.member == null)
         if(that.member == null)
            return 0; //equal
         else
            return -1; // null is before other strings
       else // this.member != null
         if(that.member == null)
            return 1;  // all other strings are after null
         else
            return this.member.compareTo(that.member);
   }
}

Обратите внимание, что спецификация Comparable.compareTo() имеет только ограничение для o.compareTo(null) (который должен вести себя так же, как - null.compareTo(o), то есть бросить NullPointerException), но не о том, как null поля обрабатываются (в нем вообще не упоминаются поля, поэтому класс может возвращать все, что ему нужно, при условии, что обеспечивается антисимметрия, рефлексивность и транзитивность).

Ответ 2

Из javadoc для Comparable

Обратите внимание, что null не является экземпляром любой класс и e.compareTo(null) должен вызывать исключение NullPointerException даже если e.equals(null) возвращает ложь.

Ответ 3

Было бы плохой практикой не бросать исключение, потому что оно нарушает антисимметричный характер сравнения .

Из Документация Comparable.compareTo:

Разработчик должен обеспечить sgn (x.compareTo(y)) == -sgn (y.compareTo(x)) для всех x и y. (Это означает, что x.compareTo(y) должен исключить iff y.compareTo(x) выдает исключение.)

Разработчик должен также обеспечить, чтобы отношение транзитивно: (x.compareTo(y) > 0 & y.compareTo(z) > 0) подразумевает x.compareTo(z) > 0.

Наконец, разработчик должен обеспечить что x.compareTo(y) == 0 означает, что sgn (x.compareTo(z)) == sgn (y.compareTo(z)), для всех z.

Что еще более важно, это плохая идея использовать compareTo для ваших объектов для сравнения их со строками по той же причине: sign(obj.compareTo(str)) != -sign(str.compareTo(obj)). Внедрите пользовательский Comparator и сделайте то, что вы хотите в нем.

Ответ 4

Поскольку в документации compareTo указано, что он должен бросить NullPointerException, вы должны следовать этим рекомендациям, чтобы ваша реализация соответствовала документации интерфейса. Это также обрабатывает вопросы о том, являются ли ненулевые строки лексикографически меньше или больше, чем null.

У вас есть несколько вариантов того, как справиться с этим. Если пустые и не применимые разные, то вы, вероятно, должны перенести поле строки в свой собственный класс полей. Например, предположим, что вы можете создать тип MyField, который может иметь метод isApplicable, который указывает, применимо ли поле к этому случаю (или что-то подобное). Или вы можете переосмыслить свой дизайн и быть уверенным, что пустая строка и N/A действительно две разные вещи. Если да, то вам нужен способ разграничения между ними.

Ответ 5

Вам нужно решить, имеет ли значение null больше или меньше, чем значение, отличное от нуля. Вы можете проектировать compareTo для удовлетворения потребностей естественного упорядочения вашего класса, поэтому это не плохая практика.