1. Обзор
EnumMap
— это реализация Map
, которая использует исключительно Enum
в качестве своих ключей.
В этом уроке мы обсудим его свойства, распространенные варианты использования и когда мы должны его использовать.
2. Настройка проекта
Представьте себе простое требование, в котором нам нужно сопоставить дни недели со спортом, в который мы играем в этот день:
Monday Soccer
Tuesday Basketball
Wednesday Hiking
Thursday Karate
Для этого мы могли бы использовать перечисление:
public enum DayOfWeek {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
Который, как мы скоро увидим, станет ключом к нашей карте.
3. Создание
Чтобы начать изучение EnumMap
, сначала нам нужно создать его экземпляр:
EnumMap<DayOfWeek, String> activityMap = new EnumMap<>(DayOfWeek.class);
activityMap.put(DayOfWeek.MONDAY, "Soccer");
И вот наше первое отличие от чего-то более распространенного, например HashMap
. Обратите внимание, что с HashMap
достаточно параметризации типа, а это означает, что мы можем обойтись без new HashMap<>().
Однако EnumMap
требует тип ключа в конструкторе .
3.1. Конструктор копирования EnumMap
EnumMap
также поставляется с двумя конструкторами копирования. Первый принимает другой EnumMap
:
EnumMap<DayOfWeek, String> activityMap = new EnumMap<>(DayOfWeek.class);
activityMap.put(DayOfWeek.MONDAY, "Soccer");
activityMap.put(DayOfWeek.TUESDAY, "Basketball");
EnumMap<DayOfWeek, String> activityMapCopy = new EnumMap<>(dayMap);
assertThat(activityMapCopy.size()).isEqualTo(2);
assertThat(activityMapCopy.get(DayOfWeek.MONDAY)).isEqualTo("Soccer");
assertThat(activityMapCopy.get(DayOfWeek.TUESDAY)).isEqualTo("Basketball");
3.2. Конструктор копирования карты
Или, если у нас есть непустая Карта
, ключ которой является перечислением, мы можем сделать и это:
Map<DayOfWeek, String> ordinaryMap = new HashMap();
ordinaryMap.put(DayOfWeek.MONDAY, "Soccer");
EnumMap enumMap = new EnumMap(ordinaryMap);
assertThat(enumMap.size()).isEqualTo(1);
assertThat(enumMap.get(DayOfWeek.MONDAY)).isEqualTo("Soccer");
Обратите внимание, что карта должна быть непустой, чтобы EnumMap
мог определить тип ключа из существующей записи.
Если указанная карта содержит более одного типа перечисления, конструктор выдаст ClassCastException
.
4. Добавление и извлечение элементов
После создания экземпляра EnumMap
мы можем добавить наш вид спорта с помощью метода put()
:
activityMap.put(DayOfWeek.MONDAY, "Soccer");
И чтобы получить его, мы можем использовать get()
:
assertThat(clubMap.get(DayOfWeek.MONDAY)).isEqualTo("Soccer");
5. Проверка элементов
Чтобы проверить, определено ли сопоставление для определенного дня, мы используем containsKey()
:
activityMap.put(DayOfWeek.WEDNESDAY, "Hiking");
assertThat(activityMap.containsKey(DayOfWeek.WEDNESDAY)).isTrue();
И, чтобы проверить, сопоставлен ли конкретный вид спорта с каким-либо ключом, мы используем containsValue()
:
assertThat(activityMap.containsValue("Hiking")).isTrue();
5.1. ноль
как значение
Теперь null
является семантически допустимым значением для EnumMap
.
Давайте свяжем null
с «ничегонеделанием» и сопоставим его с субботой:
assertThat(activityMap.containsKey(DayOfWeek.SATURDAY)).isFalse();
assertThat(activityMap.containsValue(null)).isFalse();
activityMap.put(DayOfWeek.SATURDAY, null);
assertThat(activityMap.containsKey(DayOfWeek.SATURDAY)).isTrue();
assertThat(activityMap.containsValue(null)).isTrue();
6. Удаление элементов
Чтобы отменить отображение определенного дня, мы просто удаляем()
его:
activityMap.put(DayOfWeek.MONDAY, "Soccer");
assertThat(activityMap.remove(DayOfWeek.MONDAY)).isEqualTo("Soccer");
assertThat(activityMap.containsKey(DayOfWeek.MONDAY)).isFalse();
Как мы видим, remove(key)
возвращает предыдущее значение, связанное с ключом, или null
, если для ключа не было сопоставления.
Мы также можем отменить сопоставление определенного дня , только если
этот день сопоставлен с определенной деятельностью:
activityMap.put(DayOfWeek.Monday, "Soccer");
assertThat(activityMap.remove(DayOfWeek.Monday, "Hiking")).isEqualTo(false);
assertThat(activityMap.remove(DayOfWeek.Monday, "Soccer")).isEqualTo(true);
remove(key, value)
удаляет запись для указанного ключа, только если этот ключ в настоящее время сопоставлен с указанным значением.
7. Представления коллекции
Как и в случае с обычными картами, с любым EnumMap
у нас может быть 3 разных представления или подколлекции.
Во-первых, давайте создадим новую карту нашей деятельности:
EnumMap<DayOfWeek, String> activityMap = new EnumMap(DayOfWeek.class);
activityMap.put(DayOfWeek.THURSDAY, "Karate");
activityMap.put(DayOfWeek.WEDNESDAY, "Hiking");
activityMap.put(DayOfWeek.MONDAY, "Soccer");
7.1. ценности
Первое представление нашей карты активности — это values()
, которое, как следует из названия, возвращает все значения на карте:
Collection values = dayMap.values();
assertThat(values)
.containsExactly("Soccer", "Hiking", "Karate");
Обратите внимание, что EnumMap
— это упорядоченная карта. Он использует порядок перечисления DayOfWeek
для определения порядка записей.
7.2. набор ключей
Точно так же keySet()
возвращает набор ключей, опять же в порядке перечисления:
Set keys = dayMap.keySet();
assertThat(keys)
.containsExactly(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.SATURDAY);
7.3. записьНабор
Наконец, entrySet()
возвращает сопоставление в виде пар ключа и значения:
assertThat(dayMap.entrySet())
.containsExactly(
new SimpleEntry(DayOfWeek.MONDAY, "Soccer"),
new SimpleEntry(DayOfWeek.WEDNESDAY, "Hiking"),
new SimpleEntry(DayOfWeek.THURSDAY, "Karate")
);
Упорядочивание на карте, безусловно, может пригодиться, и мы углубимся в наше руководство, которое сравнивает TreeMap с HashMap .
7.4. Изменчивость
Теперь помните, что любые изменения, которые мы вносим в исходную карту активности, будут отражены в любом из ее представлений:
activityMap.put(DayOfWeek.TUESDAY, "Basketball");
assertThat(values)
.containsExactly("Soccer", "Basketball", "Hiking", "Karate");
Наоборот; любые изменения, которые мы вносим в подвиды, будут отражены в исходной карте активности:
values.remove("Hiking");
assertThat(activityMap.containsKey(DayOfWeek.WEDNESDAY)).isFalse();
assertThat(activityMap.size()).isEqualTo(3);
Согласно контракту EnumMap
с интерфейсом Map
, дополнительные представления поддерживаются исходной картой.
8. Когда использовать EnumMap
8.1. Производительность
Использование Enum
в качестве ключа позволяет выполнить некоторую дополнительную оптимизацию производительности, например, более быстрое вычисление хеш-функции, поскольку все возможные ключи известны заранее.
Простота использования enum
в качестве ключа означает , что для EnumMap
требуется только резервная копия старого простого массива
Java с очень простой логикой для хранения и поиска. С другой стороны, общие реализации Map
должны учитывать проблемы, связанные с наличием универсального объекта в качестве его ключа. Например, HashMap
требует сложной структуры данных и значительно более сложной логики хранения и поиска, чтобы учесть возможность коллизии хэшей.
8.2. Функциональность
Кроме того, как мы видели, EnumMap
является упорядоченной картой, поскольку ее представления будут повторяться в порядке перечисления. Чтобы получить подобное поведение для более сложных сценариев, мы можем посмотреть на TreeMap
или LinkedHashMap
.
9. Заключение
В этой статье мы рассмотрели реализацию EnumMap
интерфейса Map .
При работе с Enum
в качестве ключа EnumMap
может пригодиться.
Полный исходный код всех примеров, использованных в этом руководстве, можно найти в проекте GitHub .