Coleções Apache Commons OrderedMap

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.