Статьи

NetBeans в классе: обязательные методы для бобов (часть 3)


колледже Доусон в Монреале, Канада. Он также является программным консультантом и по совместительству преподавателем в Школе расширенного обучения при Институте вычислительной техники Университета Конкордия . Он ведет блог на omniprogrammer.com и пишет в Твиттере @omniprof . Его регулярные колонки о NetBeans в образовании перечислены здесь .

В следующей статье о бинах и новичках, начиная с части 1 и части 2 , я рассмотрю интерфейс Comparable и метод compareTo. В предыдущей статье я добавил интерфейс для bean-компонента и метод-заполнитель.

public class MyCarBean implements Comparable<MyCarBean> {
  @Override
  public int compareTo(MyCarBean o) {
     throw new UnsupportedOperationException("Not supported yet."); 
  }

Две операции, которые часто выполняются при работе с несколькими экземплярами объектов, — это поиск и сортировка. Поиск поддерживается методами equals и hashCode. Сортировка поддерживается методом сравнения. Если мои bean-компоненты находятся в массиве, то метод Arrays.sort ожидает найти метод CompareTo.

Метод compareTo получает объект того же типа, что и сам, и вам решать, какие правила будут определять результат. Метод equals возвращает логическое значение и поэтому может возвращать одно из двух возможных состояний. Метод hashCode возвращает вычисленное значение хеша, которое для меня является просто одним состоянием. Метод compareTo возвращает одно из трех возможных значений и имеет три состояния. Это меньше, равно и больше, чем.

Обычно предполагается, что три значения -1, 0 и +1. Это предположение неверно. Значение 0 означает, что объект, с которым вы сравниваете себя, является одним и тем же. Однако значения для обозначения двух других состояний основаны на знаке (положительном или отрицательном) результата, а не на фактическом значении результата. Это важно помнить, потому что вы должны писать код так, чтобы все сравнения были относительно нуля.

// Wrong way, look at the else if
if (carBean1.compareTo(carBean2) == 0) { // equal
  System.out.println("Bean1 is the same as Bean2");
} else if (carBean1.compareTo(carBean2) == 1) { // Comparing to +1
  System.out.println("Bean1 is the greater than Bean2");
} else { // Not 0 or +1 so must be -1
  System.out.println("Bean1 is the less than Bean2");
}
// Right way
if (carBean1.compareTo(carBean2) == 0) { // equal
  System.out.println("Bean1 is the same as Bean2");
} else if (carBean1.compareTo(carBean2) > 0) { // positive >
  System.out.println("Bean1 is the greater than Bean2");
} else { // negative <
  System.out.println("Bean1 is the less than Bean2");
}

Теперь осталось только написать метод compareTo. Когда NetBeans пишет для нас метод equals, он пишет код, который сравнивает каждого члена класса. Затем мы можем удалить любых сравниваемых членов, если они не имеют отношения к равенству. Поскольку CompareTo не написано для нас, мы должны сразу решить, как мы будем определять порядок объекта. Мы редко будем использовать каждого члена класса, чтобы сделать это определение, если в классе нет только одного члена.

Моим примером в этих статьях был бин, представляющий информацию, наиболее часто встречающуюся в рекламе автомобилей. Если я создал бобы для десяти разных автомобилей, а затем добавил их в массив, то какой порядок мне ожидать, если я отсортировал массив? Вы можете думать об этом решении одним из двух способов. Если используется только одно поле, то это похоже на решение, каким будет первичный ключ для таблицы реляционной базы данных. Если вы используете два или более полей, вы создаете что-то похожее на основной / подробный отчет. Это мастер / деталь, которую я выбрал.

Я буду использовать двух членов класса, производителя и модели. Таким образом, все автомобили от производителя будут сгруппированы, и в каждой группе они будут упорядочены по моделям. Производитель и модель — это строковые объекты и строковые перегрузки.

В случае, если объект, переданный в CompareTo, имеет значение null, тогда NullPointerException будет выброшено при выполнении кода, который обращается к члену объекта. Было бы неплохо использовать предложение throws, но поскольку интерфейс Comparable этого не делает, я не могу. Вот почему заголовок метода содержит тег @throws, чтобы сообщить пользователю об этой возможности. Нулевые ссылки редко следует вставлять в массив или коллекцию.

/**
 * Orders by the String for manufacturer and if they are the same then
 * order by the model. String objects implement the Comparable interface
 *
 * @param otherbean is a non-null MyCarBean object\
 * @return <0, 0 or >0
 * @throws NullPointerException if otherBean is null
 */
@Override
public int compareTo(MyCarBean otherBean) {
  int retVal = 0; // See the paragraph after this code
  // Step 1: Check if we are comparing the bean to itself
  if (this == otherBean) {
    retVal = 0;
  } else { // Step 2: Check the manufacturer, continuing if it is equal 
    int comparison = 
      this.manufacturer.compareTo(otherBean.manufacturer);
    if (comparison != 0) { // Not equal so no need to look at the model
      retVal = comparison;
    } else {  // Step 3: Manufacturers were the same so compare the model
      retVal = this.model.compareTo(otherBean.model);
    }
 }
 return retVal;
}

Я начал кодировать в структурированную эпоху. Один из идеалов этого подхода заключается в том, что каждая функция-методор должна иметь одну точку входа и одну точку выхода. Поэтому я обучаю своих студентов технике, которую вы видите в этом методе, где я использую переменную с именем retVal, которая содержит то, что будет возвращено. Используя if / else мой код может иметь одну точку выхода. Я постепенно признаю, что этот идеал был заброшен большинством программистов. Поэтому код, скорее всего, будет выглядеть так:

@Override
public int compareTo(MyCarBean otherBean) {
    // Step 1: Check if we are comparing the bean to itself
    if (this == otherBean) {
        return 0;
    }
    // Step 2: Check the manufacturer, continuing if it is equal 
    int comparison
            = this.manufacturer.compareTo(otherBean.manufacturer);
    // Not equal so no need to look at the model
    if (comparison != 0) {
        return comparison;
    }
    // Step 3: Manufacturers were the same so compare the model
    return this.model.compareTo(otherBean.model);
}

Я давно признал, что есть два подхода к кодированию. Академический и прагматичный. Единственное возвращение является академическим, а стая возвращений прагматична. Я буду продолжать учиться, и когда мои студенты закончат обучение, они могут стать прагматичными.