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 .