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

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

1. обзор

Apache Commons Collections library предоставляет полезные классы, которые дополняют Java Collections Framework.

В этой статье мы рассмотрим интерфейсOrderedMap, расширяющийjava.util.Map.

2. Maven Dependency

Первое, что нам нужно сделать, это добавить зависимость Maven в нашpom.xml:


    org.apache.commons
    commons-collections4
    4.1

Вы можете найти последнюю версию библиотеки наMaven Central repository.

3. OrderedMap Свойства

Проще говоря, карта, реализующая интерфейсOrderedMap:

  • Поддерживает порядок в наборе ключей, хотя набор не отсортирован

  • Может повторяться в обоих направлениях с помощью методов:firstKey() иnextKey(), илиlastKey() иpreviousKey()

  • Можно пройти с помощьюMapIterator (также предоставляется библиотекой)

  • Предоставляет методы для поиска, изменения, удаления или замены элементов

4. ИспользуяOrderedMap

Давайте установимOrderedMapбегунов и их возраст в тестовом классе. Мы будем использоватьLinkedMap - одну из реализацийOrderedMap, представленных в библиотеке.

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

public class OrderMapUnitTest {
    private String[] names = {"Emily", "Mathew", "Rose", "John", "Anna"};
    private Integer[] ages = {37, 28, 40, 36, 21};
    private LinkedMap runnersLinkedMap;

    //...
}

Теперь давайте инициализируем нашу карту:

@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. Прямая итерация

Давайте посмотрим, как используется прямой итератор:

@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++;
    }
}

Обратите внимание, что когда мы достигли последнего ключа, методnextKey() вернет значениеnull.

4.2. Обратная итерация

Теперь вернемся назад, начиная с последнего ключа:

@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--;
    }
}

Как только мы дойдем до первого ключа, методpreviousKey() вернет null.

4.3. MapIterator Пример

Теперь давайте рассмотримuse the mapIterator() method to obtain a MapIterator, поскольку мы покажем, как он сохраняет порядок бегунов, как определено в массивахnames иages:

@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. Удаление элементов

Наконец, давайте проверим, какan 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. Предоставляемые реализации

В настоящее время в версии 4.1 библиотеки есть две реализации интерфейсаOrderedMap -ListOrderedMap иLinkedMap.

ListOrderedMap отслеживает порядок набора ключей с помощьюjava.util.List. Это декораторOrderedMap, который может быть создан из любогоMap с помощью статического методаListOrderedMap.decorate(Map map).

LinkedMap основан наHashMap и улучшает его, позволяя двунаправленную итерацию и другие методы интерфейсаOrderedMap.

Both implementations also provide three methods that are outside the OrderedMap interface:

  • asList() - получает список типаList<K> (гдеK - тип ключей) с сохранением порядка отображения

  • get(int index) - получает элемент в позицииindex в отличие от методаget(Object o), предусмотренного в интерфейсе

  • indexOf(Object o) - получает индекс объектаo в упорядоченной карте

Мы можем преобразоватьOrderedMap вLinkedMap, чтобы использовать методasList():

@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);
}

Затем мы можем проверить работу методовindexOf(Object o) иget(int index) в реализацииLinkedMap:

@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. Заключение

В этом кратком руководстве мы рассмотрели интерфейсOrderedMap, а также его основные методы и реализации.

Для получения дополнительной информации см.the JavaDoc of the Apache Commons Collections library.

Как всегда, полный тестовый класс для этой статьи содержит аналогичные тестовые примеры, в которых используются какLinkedMap, так иListOrderedMap, и его можно загрузить изGitHub project.