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

Коллекции Apache Commons MapUtils

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

Упражнение: Сложение двух чисел

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

ANDROMEDA

1. Введение

MapUtils — это один из инструментов, доступных в проекте Apache Commons Collections.

Проще говоря, он предоставляет служебные методы и декораторы для работы с экземплярами java.util.Map и java.util.SortedMap .

2. Настройка

Начнем с добавления зависимости :

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>

3. Вспомогательные методы

3.1. Создание карты из массива

Теперь давайте настроим массивы, которые мы будем использовать для создания карты:

public class MapUtilsTest {
private String[][] color2DArray = new String[][] {
{"RED", "#FF0000"},
{"GREEN", "#00FF00"},
{"BLUE", "#0000FF"}
};
private String[] color1DArray = new String[] {
"RED", "#FF0000",
"GREEN", "#00FF00",
"BLUE", "#0000FF"
};
private Map<String, String> colorMap;

//...
}

Давайте посмотрим, как мы можем создать карту из двумерного массива:

@Test
public void whenCreateMapFrom2DArray_theMapIsCreated() {
this.colorMap = MapUtils.putAll(
new HashMap<>(), this.color2DArray);

assertThat(
this.colorMap,
is(aMapWithSize(this.color2DArray.length)));

assertThat(this.colorMap, hasEntry("RED", "#FF0000"));
assertThat(this.colorMap, hasEntry("GREEN", "#00FF00"));
assertThat(this.colorMap, hasEntry("BLUE", "#0000FF"));
}

Мы также могли бы использовать одномерный массив. В этом случае массив обрабатывается как ключи и значения в альтернативных индексах:

@Test
public void whenCreateMapFrom1DArray_theMapIsCreated() {
this.colorMap = MapUtils.putAll(
new HashMap<>(), this.color1DArray);

assertThat(
this.colorMap,
is(aMapWithSize(this.color1DArray.length / 2)));

assertThat(this.colorMap, hasEntry("RED", "#FF0000"));
assertThat(this.colorMap, hasEntry("GREEN", "#00FF00"));
assertThat(this.colorMap, hasEntry("BLUE", "#0000FF"));
}

3.2. Печать содержимого карты

Много раз во время отладки или в журналах отладки мы хотели бы распечатать всю карту:

@Test
public void whenVerbosePrintMap_thenMustPrintFormattedMap() {
MapUtils.verbosePrint(System.out, "Optional Label", this.colorMap);
}

И результат:

Optional Label = 
{
RED = #FF0000
BLUE = #0000FF
GREEN = #00FF00
}

Мы также можем использовать debugPrint() , который дополнительно печатает типы данных значений.

3.3. Получение значений

MapUtils предоставляет несколько методов для извлечения значения из карты для заданного ключа нулевым безопасным способом.

Например, getString() получает строку из карты . Значение String получается с помощью toString() . При желании мы можем указать значение по умолчанию, которое будет возвращено, если значение равно null или если преобразование не удалось:

@Test
public void whenGetKeyNotPresent_thenMustReturnDefaultValue() {
String defaultColorStr = "COLOR_NOT_FOUND";
String color = MapUtils
.getString(this.colorMap, "BLACK", defaultColorStr);

assertEquals(color, defaultColorStr);
}

Обратите внимание, что эти методы безопасны для нулей, т. е. они могут безопасно обрабатывать нулевой параметр карты:

@Test
public void whenGetOnNullMap_thenMustReturnDefaultValue() {
String defaultColorStr = "COLOR_NOT_FOUND";
String color = MapUtils.getString(null, "RED", defaultColorStr);

assertEquals(color, defaultColorStr);
}

Здесь цвет получит значение COLOR_NOT_FOUND , даже если карта имеет значение null .

3.4. Инвертирование карты

Мы также можем легко перевернуть карту:

@Test
public void whenInvertMap_thenMustReturnInvertedMap() {
Map<String, String> invColorMap = MapUtils.invertMap(this.colorMap);

int size = invColorMap.size();
Assertions.assertThat(invColorMap)
.hasSameSizeAs(colorMap)
.containsKeys(this.colorMap.values().toArray(new String[] {}))
.containsValues(this.colorMap.keySet().toArray(new String[] {}));
}

Это инвертирует colorMap в :

{
#00FF00 = GREEN
#FF0000 = RED
#0000FF = BLUE
}

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

3.5. Нулевые и пустые чеки

Метод isEmpty() возвращает значение true , если карта имеет значение null или пуста.

Метод safeAddToMap() предотвращает добавление нулевых элементов в карту.

4. Декораторы

Эти методы добавляют дополнительную функциональность к карте.

В большинстве случаев рекомендуется не хранить ссылку на декорированную карту Map .

4.1. Карта фиксированного размера ``

fixedSizeMap() возвращает карту фиксированного размера, поддерживаемую данной картой. Элементы можно изменять, но нельзя добавлять или удалять:

@Test(expected = IllegalArgumentException.class)
public void whenCreateFixedSizedMapAndAdd_thenMustThrowException() {
Map<String, String> rgbMap = MapUtils
.fixedSizeMap(MapUtils.putAll(new HashMap<>(), this.color1DArray));

rgbMap.put("ORANGE", "#FFA500");
}

4.2. Предикативная карта

Метод predicatedMap() возвращает Map и гарантирует, что все удерживаемые элементы соответствуют предоставленному предикату:

@Test(expected = IllegalArgumentException.class)
public void whenAddDuplicate_thenThrowException() {
Map<String, String> uniqValuesMap
= MapUtils.predicatedMap(this.colorMap, null,
PredicateUtils.uniquePredicate());

uniqValuesMap.put("NEW_RED", "#FF0000");
}

Здесь мы указали предикат для значений с помощью PredicateUtils.uniquePredicate() . Любая попытка вставить повторяющееся значение в эту карту приведет к ошибке java.lang. Недопустимое АргументИсключение .

Мы можем реализовать пользовательские предикаты, реализовав интерфейс Predicate .

4.3. Ленивая карта

lazyMap() возвращает карту, в которой значения инициализируются по запросу.

Если ключ, переданный методу Map.get(Object) этой карты, отсутствует на карте, экземпляр Transformer будет использоваться для создания нового объекта, который будет связан с запрошенным ключом:

@Test
public void whenCreateLazyMap_theMapIsCreated() {
Map<Integer, String> intStrMap = MapUtils.lazyMap(
new HashMap<>(),
TransformerUtils.stringValueTransformer());

assertThat(intStrMap, is(anEmptyMap()));

intStrMap.get(1);
intStrMap.get(2);
intStrMap.get(3);

assertThat(intStrMap, is(aMapWithSize(3)));
}

5. Вывод

В этом кратком руководстве мы изучили класс MapUtils Apache Commons Collections и рассмотрели различные служебные методы и декораторы, которые могут упростить различные распространенные операции с картами.

Как обычно, код доступен на GitHub .