Coleções Apache Commons OrderedMap
1. Visão geral
OApache Commons Collections library fornece classes úteis que complementam o Java Collections Framework.
Neste artigo, revisaremos a interfaceOrderedMap, que estendejava.util.Map.
2. Dependência do Maven
A primeira coisa que precisamos fazer é adicionar a dependência Maven em nossopom.xml:
org.apache.commons
commons-collections4
4.1
Você pode encontrar a versão mais recente da biblioteca emMaven Central repository.
3. Propriedades deOrderedMap
Simplificando, um mapa que implementa a interfaceOrderedMap:
-
Mantém a ordem em seu conjunto de chaves, embora o conjunto não seja classificado
-
Pode ser iterado em ambas as direções com os métodos:firstKey() enextKey(), oulastKey()epreviousKey()
-
Pode ser percorrido com umMapIterator (também fornecido pela biblioteca)
-
Fornece métodos para localizar, alterar, remover ou substituir elementos
4. UsandoOrderedMap
Vamos configurar umOrderedMap dos corredores e suas idades em uma aula de teste. Usaremos umLinkedMap - uma das implementaçõesOrderedMap fornecidas na biblioteca.
Primeiro, vamos configurar matrizes de corredores e idades que usaremos para carregar o mapa e verificar a ordem dos valores:
public class OrderMapUnitTest {
private String[] names = {"Emily", "Mathew", "Rose", "John", "Anna"};
private Integer[] ages = {37, 28, 40, 36, 21};
private LinkedMap runnersLinkedMap;
//...
}
Agora, vamos inicializar nosso mapa:
@Before
public void createRunners() {
this.runnersLinkedMap = new LinkedMap<>();
for (int i = 0; i < RUNNERS_COUNT; i++) {
runners.put(this.names[i], this.ages[i]);
}
}
4.1. Iteração direta
Vamos ver como o iterador de encaminhamento é usado:
@Test
public void givenALinkedMap_whenIteratedForwards_thenPreservesOrder() {
String name = this.runnersLinkedMap.firstKey();
int i = 0;
while (name != null) {
assertEquals(name, names[i]);
name = this.runnersLinkedMap.nextKey(name);
i++;
}
}
Observe que quando alcançamos a última chave, o métodonextKey() retornará um valornull.
4.2. Iteração para trás
Agora vamos repetir, começando com a última chave:
@Test
public void givenALinkedMap_whenIteratedBackwards_thenPreservesOrder() {
String name = this.runnersLinkedMap.lastKey();
int i = RUNNERS_COUNT - 1;
while (name != null) {
assertEquals(name, this.names[i]);
name = this.runnersLinkedMap.previousKey(name);
i--;
}
}
Assim que alcançarmos a primeira chave, o métodopreviousKey() retornará nulo.
4.3. MapIterator Exemplo
Agora vamosuse the mapIterator() method to obtain a MapIterator enquanto mostramos como ele preserva a ordem dos runners conforme definido nas matrizesnameseages:
@Test
public void givenALinkedMap_whenIteratedWithMapIterator_thenPreservesOrder() {
OrderedMapIterator runnersIterator
= this.runnersLinkedMap.mapIterator();
int i = 0;
while (runnersIterator.hasNext()) {
runnersIterator.next();
assertEquals(runnersIterator.getKey(), this.names[i]);
assertEquals(runnersIterator.getValue(), this.ages[i]);
i++;
}
}
4.4. Removendo elementos
Finalmente, vamos verificar comoan element can be removed by index or by object:
@Test
public void givenALinkedMap_whenElementRemoved_thenSizeDecrease() {
LinkedMap lmap
= (LinkedMap) this.runnersLinkedMap;
Integer johnAge = lmap.remove("John");
assertEquals(johnAge, new Integer(36));
assertEquals(lmap.size(), RUNNERS_COUNT - 1);
Integer emilyAge = lmap.remove(0);
assertEquals(emilyAge, new Integer(37));
assertEquals(lmap.size(), RUNNERS_COUNT - 2);
}
5. Implementações Fornecidas
Atualmente, na versão 4.1 da biblioteca, existem duas implementações da interfaceOrderedMap -ListOrderedMapeLinkedMap.
ListOrderedMap mantém o controle da ordem do conjunto de chaves usando umjava.util.List. É um decorador deOrderedMape pode ser criado a partir de qualquerMap usando o método estáticoListOrderedMap.decorate(Map map).
LinkedMap é baseado emHashMap e o aprimora permitindo a iteração bidirecional e os outros métodos da interfaceOrderedMap.
Both implementations also provide three methods that are outside the OrderedMap interface:
-
asList() - obtém uma lista do tipoList<K> (ondeK é o tipo das chaves) preservando a ordem do mapa
-
get(int index) - obtém o elemento na posiçãoindex em oposição ao métodoget(Object o) fornecido na interface
-
indexOf(Object o) - obtém o índice do objetoo no mapa ordenado
Podemos converterOrderedMap em umLinkedMap para usar o métodoasList():
@Test
public void givenALinkedMap_whenConvertedToList_thenMatchesKeySet() {
LinkedMap lmap
= (LinkedMap) this.runnersLinkedMap;
List listKeys = new ArrayList<>();
listKeys.addAll(this.runnersLinkedMap.keySet());
List linkedMap = lmap.asList();
assertEquals(listKeys, linkedMap);
}
Então podemos verificar o funcionamento do métodoindexOf(Object o)eget(int index) na implementaçãoLinkedMap:
@Test
public void givenALinkedMap_whenSearchByIndexIsUsed_thenMatchesConstantArray() {
LinkedMap lmap
= (LinkedMap) this.runnersLinkedMap;
for (int i = 0; i < RUNNERS_COUNT; i++) {
String name = lmap.get(i);
assertEquals(name, this.names[i]);
assertEquals(lmap.indexOf(this.names[i]), i);
}
}
6. Conclusão
Neste tutorial rápido, revisamos a interfaceOrderedMap e seus métodos e implementações principais.
Para obter mais informações, consultethe JavaDoc of the Apache Commons Collections library.
Como sempre, a classe de teste completa para este artigo contém casos de teste semelhantes usandoLinkedMapeListOrderedMape pode ser baixada deGitHub project.