Перейти к основному содержимому

Руководство по Apache Commons MultiValuedMap

· 5 мин. чтения

Задача: Сумма двух чисел

Напишите функцию twoSum. Которая получает массив целых чисел nums и целую сумму target, а возвращает индексы двух чисел, сумма которых равна target. Любой набор входных данных имеет ровно одно решение, и вы не можете использовать один и тот же элемент дважды. Ответ можно возвращать в любом порядке...

ANDROMEDA

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 .