1. Обзор
В этом кратком руководстве мы рассмотрим интерфейс MultiValuedMap
, предоставляемый в библиотеке Apache Commons Collections .
MultiValuedMap
предоставляет простой API для сопоставления каждого ключа с набором значений в Java. Это преемник org.apache.commons.collections4.MultiMap ,
который устарел в Commons Collection 4.1.
2. Зависимость от Maven
Для проектов Maven нам нужно добавить зависимость commons-collections4 :
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.2</version>
</dependency>
3. Добавление элементов в MultiValuedMap
Мы можем добавлять элементы, используя методы put
и putAll
.
Начнем с создания экземпляра MultiValuedMap
:
MultiValuedMap<String, String> map = new ArrayListValuedHashMap<>();
Далее давайте посмотрим, как мы можем добавлять элементы по одному, используя метод put
:
map.put("fruits", "apple");
map.put("fruits", "orange");
Кроме того, давайте добавим некоторые элементы с помощью метода putAll
, который сопоставляет ключ нескольким элементам за один вызов:
map.putAll("vehicles", Arrays.asList("car", "bike"));
assertThat((Collection<String>) map.get("vehicles"))
.containsExactly("car", "bike");
4. Извлечение элементов из MultiValuedMap
MultiValuedMap
предоставляет методы для извлечения ключей, значений и сопоставлений ключ-значение. Давайте посмотрим на каждый из них.
4.1. Получить все значения ключа
Чтобы получить все значения, связанные с ключом, мы можем использовать метод get
, который возвращает Collection
:
assertThat((Collection<String>) map.get("fruits"))
.containsExactly("apple", "orange");
4.2. Получить все сопоставления ключ-значение
Или мы можем использовать метод entry
для получения коллекции
всех сопоставлений ключ-значение, содержащихся в карте:
Collection<Map.Entry<String, String>> entries = map.entries();
4.3. Получить все ключи
Существует два метода получения всех ключей, содержащихся в MultiValuedMap.
Давайте воспользуемся методом keys
, чтобы получить представление MultiSet
для ключей:
MultiSet<String> keys = map.keys();
assertThat(keys).contains("fruits", "vehicles");
В качестве альтернативы мы можем получить набор
ключей, используя метод keySet
:
Set<String> keys = map.keySet();
assertThat(keys).contains("fruits", "vehicles");
4.4. Получить все значения карты
Наконец, если мы хотим получить представление коллекции
всех значений, содержащихся на карте, мы можем использовать метод значений
:
Collection<String> values = map.values();
assertThat(values).contains("apple", "orange", "car", "bike");
5. Удаление элементов из MultiValuedMap
Теперь давайте рассмотрим все методы удаления элементов и сопоставления ключ-значение.
5.1. Удалить все элементы, сопоставленные с ключом
Во-первых, давайте посмотрим, как удалить все значения, связанные с указанным ключом, с помощью метода удаления
:
Collection<String> removedValues = map.remove("fruits");
assertThat(map.containsKey("fruits")).isFalse();
assertThat(removedValues).contains("apple", "orange");
Этот метод возвращает представление коллекции
удаленных значений.
5.2. Удалить одно сопоставление "ключ-значение"
Теперь предположим, что у нас есть ключ, сопоставленный с несколькими значениями, но мы хотим удалить только одно из сопоставленных значений, оставив остальные. Мы можем легко сделать это, используя метод removeMapping
:
boolean isRemoved = map.removeMapping("fruits","apple");
assertThat(map.containsMapping("fruits","apple")).isFalse();
5.3. Удалить все сопоставления ключ-значение
И, наконец, мы можем использовать метод clear
для удаления всех сопоставлений с карты:
map.clear();
assertThat(map.isEmpty()).isTrue();
6. Проверка элементов из MultiValuedMap
Далее давайте рассмотрим различные методы проверки существования указанного ключа или значения в нашей карте.
6.1. Проверить, существует ли ключ
Чтобы узнать, содержит ли наша карта отображение для указанного ключа, мы можем использовать метод containsKey
:
assertThat(map.containsKey("vehicles")).isTrue();
6.2. Проверить, существует ли значение
Далее предположим, что мы хотим проверить, содержит ли хотя бы один ключ в нашей карте сопоставление для определенного значения. Мы можем сделать это с помощью метода containsValue
:
assertThat(map.containsValue("orange")).isTrue();
6.3. Проверьте, существует ли сопоставление ключ-значение
Точно так же, если мы хотим проверить, содержит ли карта сопоставление для определенной пары ключ-значение, мы можем использовать метод containsMapping
:
assertThat(map.containsMapping("fruits","orange")).isTrue();
6.4. Проверить, пуста ли карта
Чтобы проверить, не содержит ли карта вообще каких-либо сопоставлений ключ-значение, мы можем использовать метод isEmpty
:
assertThat(map.isEmpty()).isFalse;
6.5. Проверьте размер карты
Наконец, мы можем использовать метод size
, чтобы получить общий размер карты. Когда карта имеет ключи с несколькими значениями, общий размер карты равен количеству всех значений всех ключей:
assertEquals(4, map.size());
7. Реализации
Библиотека коллекций Apache Commons также предоставляет несколько реализаций этого интерфейса. Давайте посмотрим на них.
7.1. ArrayListValuedHashMap
ArrayListValuedHashMap внутренне
использует ArrayList
для хранения значений, связанных с каждым ключом, поэтому он позволяет дублировать пары ключ-значение : `` ****
MultiValuedMap<String, String> map = new ArrayListValuedHashMap<>();
map.put("fruits", "apple");
map.put("fruits", "orange");
map.put("fruits", "orange");
assertThat((Collection<String>) map.get("fruits"))
.containsExactly("apple", "orange", "orange");
Теперь стоит отметить, что этот класс не является потокобезопасным . Поэтому, если мы хотим использовать эту карту из нескольких потоков, мы должны обязательно использовать правильную синхронизацию.
7.2. HashSetValuedHashMap
HashSetValuedHashMap использует
HashSet
для хранения значений для каждого заданного ключа. Поэтому он не допускает дублирования пар ключ-значение .
Давайте посмотрим на быстрый пример, где мы дважды добавляем одно и то же сопоставление ключ-значение:
MultiValuedMap<String, String> map = new HashSetValuedHashMap<>();
map.put("fruits", "apple");
map.put("fruits", "apple");
assertThat((Collection<String>) map.get("fruits"))
.containsExactly("apple");
Обратите внимание, что в отличие от нашего предыдущего примера, в котором использовался ArrayListValuedHashMap,
реализация HashSetValuedHashMap
игнорирует повторяющееся сопоставление.
Класс HashSetValuedHashMap
также не является потокобезопасным .
7.3. Немодифицируемая многозначная карта
UnmodifiedMultiValuedMap
— это класс - декоратор, который полезен, когда нам нужен неизменяемый экземпляр MultiValuedMap
, то есть он не должен допускать дальнейших модификаций:
@Test(expected = UnsupportedOperationException.class)
public void givenUnmodifiableMultiValuedMap_whenInserting_thenThrowingException() {
MultiValuedMap<String, String> map = new ArrayListValuedHashMap<>();
map.put("fruits", "apple");
map.put("fruits", "orange");
MultiValuedMap<String, String> immutableMap =
MultiMapUtils.unmodifiableMultiValuedMap(map);
immutableMap.put("fruits", "banana"); // throws exception
}
И снова стоит отметить, что изменение окончательного варианта
приведет к исключению UnsupportedOperationException
.
8. Заключение
Мы видели различные методы интерфейса MultiValuedMap
из библиотеки Apache Commons Collections. Кроме того, мы рассмотрели несколько популярных реализаций.
И, как всегда, полный исходный код доступен на Github .