Coleções Apache Commons MapUtils
1. Introdução
MapUtils é uma das ferramentas disponíveis no projeto Apache Commons Collections.
Simplificando, ele fornece métodos utilitários e decoradores para trabalhar com instânciasjava.util.Mapejava.util.SortedMap.
2. Configuração
Vamos começar adicionandothe dependency:
org.apache.commons
commons-collections4
4.1
3. Métodos Utilitários
3.1. Criando umMap a partir de umArray
Agora, vamos configurar os arrays que usaremos para criar um mapa:
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 colorMap;
//...
}
Vamos ver como podemos criar um mapa a partir de uma matriz bidimensional:
@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"));
}
Também poderíamos usar uma matriz unidimensional. Nesse caso, a matriz é tratada como chaves e valores em índices alternativos:
@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. Imprimindo o conteúdo de umMap
Muitas vezes, durante a depuração ou nos logs de depuração, gostaríamos de imprimir o mapa inteiro:
@Test
public void whenVerbosePrintMap_thenMustPrintFormattedMap() {
MapUtils.verbosePrint(System.out, "Optional Label", this.colorMap);
}
E o resultado:
Optional Label =
{
RED = #FF0000
BLUE = #0000FF
GREEN = #00FF00
}
Também podemos usardebugPrint() que adicionalmente imprime os tipos de dados dos valores.
3.3. Obtendo Valores
MapUtils fornece alguns métodos para extrair valor de um mapa para uma determinada chave de maneiranull-safe.
Por exemplo,getString() obtém umString deMap. O valor deString é obtido por meio detoString(). Podemos opcionalmente especificar o valor padrão a ser retornado se o valor fornull ou se a conversão falhar:
@Test
public void whenGetKeyNotPresent_thenMustReturnDefaultValue() {
String defaultColorStr = "COLOR_NOT_FOUND";
String color = MapUtils
.getString(this.colorMap, "BLACK", defaultColorStr);
assertEquals(color, defaultColorStr);
}
Observe que esses métodos sãonull-seguros, ou seja, eles podem lidar com segurança com o parâmetro de mapanull:
@Test
public void whenGetOnNullMap_thenMustReturnDefaultValue() {
String defaultColorStr = "COLOR_NOT_FOUND";
String color = MapUtils.getString(null, "RED", defaultColorStr);
assertEquals(color, defaultColorStr);
}
Aqui ocolor obteria o valor comoCOLOR_NOT_FOUND, embora o mapa sejanull.
3.4. Invertendo oMap
Também podemos reverter facilmente um mapa:
@Test
public void whenInvertMap_thenMustReturnInvertedMap() {
Map 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[] {}));
}
Isso inverteria ocolorMap em:
{
#00FF00 = GREEN
#FF0000 = RED
#0000FF = BLUE
}
Se o mapa de origem associar o mesmo valor a várias chaves, após a inversão, um dos valores se tornará uma chave aleatoriamente.
3.5. Cheques nulos e vazios
O métodoisEmpty() retornatrue se aMap fornull ou vazio.
O métodosafeAddToMap() evita a adição de elementos nulos a umMap.
4. Decoradores
Esses métodos adicionam funcionalidade adicional a umMap.
Na maioria dos casos, é uma boa prática não armazenar a referência ao mapa decorado.
4.1. Tamanho fixoMap
fixedSizeMap() retorna um mapa de tamanho fixo apoiado pelo mapa fornecido. Os elementos podem ser alterados, mas não adicionados ou removidos:
@Test(expected = IllegalArgumentException.class)
public void whenCreateFixedSizedMapAndAdd_thenMustThrowException() {
Map rgbMap = MapUtils
.fixedSizeMap(MapUtils.putAll(new HashMap<>(), this.color1DArray));
rgbMap.put("ORANGE", "#FFA500");
}
4.2. PredicadoMap
O métodopredicatedMap() retorna umMap garante que todos os elementos mantidos correspondam ao predicado fornecido:
@Test(expected = IllegalArgumentException.class)
public void whenAddDuplicate_thenThrowException() {
Map uniqValuesMap
= MapUtils.predicatedMap(this.colorMap, null,
PredicateUtils.uniquePredicate());
uniqValuesMap.put("NEW_RED", "#FF0000");
}
Aqui, especificamos o predicado para valores usandoPredicateUtils.uniquePredicate(). Qualquer tentativa de inserir um valor duplicado neste mapa resultará emjava.lang.IllegalArgumentException.
Podemos implementar predicados personalizados implementando a interfacePredicate.
4.3. PreguiçosoMap
lazyMap() retorna um mapa onde os valores são inicializados quando solicitados.
Se uma chave passada para o métodoMap.get(Object) deste mapa não estiver presente no mapa, a instânciaTransformer será usada para criar um novo objeto que será associado à chave solicitada:
@Test
public void whenCreateLazyMap_theMapIsCreated() {
Map 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. Conclusão
Neste tutorial rápido, exploramos a classe Apache Commons CollectionsMapUtils e vimos vários métodos de utilitário e decoradores que podem simplificar várias operações de mapa comuns.
Como de costume, o código está disponívelover on GitHub.