Рубрики
Без рубрики

Эффективная Java! Используйте EnumMap вместо порядкового индексирования

Погружение в главу 37 “Эффективная Java”. Помеченный как java, эффективный, перечисление, архитектура.

Мы снова рассмотрим другой специальный тип коллекции, который эффективно обрабатывает перечисления . На этот раз мы рассмотрим EnumMap s. Давайте рассмотрим некоторый код, который не использует EnumMap и вместо этого использует встроенную функцию порядковый номер . Как обсуждалось в предыдущей главе, это функция, которая должна использоваться только внутренними библиотеками, а не нашим кодом.

class PLant {
  enum LifeCycle {ANNUAL, PERENNIAL, BIENNIAL }

  final String name;
  final LifeCycle lifeCycle;

  Plant(String name, LifeCycle lifecycle) {
    this.name = name;
    this.lifecycle = lifecycle;
  }

  @Override
  public String toString() {
    return name;
  }
}

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

// Using ordinal() to index into an array. Boo.
Set[] plantsByLifecycle = (Set[]) new Set[Plant.LifeCycle.values().length];

for (int i=0; i < plantsByLifeCycle.length; i++) {
  plantsByLifeCycle[i] = new HashSet<>();
}

for (Plant p : garden) {
  plantsByLifeCycle[p.lifeCycle.ordinal()].add(p);
}

for (int i = 0; i < plantsByLifeCycle.length; i++) {
  System.out.printf("%s: %s%n", Plant.LifeCycle.values()[i], plantsByLifeCycle[i]);
}

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

Теперь давайте рассмотрим EnumMap версия того же кода:

Map> plantsByLifeCycle = new EnumMap<>(Plant.LifeCycle.class);

for (Plant.LifeCycle lc : Plant.LifeCycle.values()) {
  plantsByLifeCycle.put(lc, new HashSet<>());
}

for (Plant p : garden) {
  plantsByLifeCycle.get(p.lifeCycle).add(p);
}

System.out.println(plantsByLifecycle);

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

System.out.println(Arrays.stream(garden).collect(groupingBy(p -> p.lifeCycle, () -> new EnumMap<>(LifeCycle.class), toSet())));

Это гораздо более кратко и все же вполне понятно. Разве нам не нужно использовать реализацию Collectors.groupingBy , которая позволяет включать фабрику карт , чтобы она создавала EnumMap вместо традиционной карты реализация, которую это создало бы.

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

Оригинал: “https://dev.to/kylec32/effective-java-use-enummap-instead-of-ordinal-indexing-3o”