«1. Обзор

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

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

2. Зависимость Maven

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

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.1</version>
</dependency>

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

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<String, Integer> 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() вернет нулевое значение.

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

Теперь давайте воспользуемся методом mapIterator() для получения MapIterator, поскольку мы покажем, как он сохраняет порядок бегунов, определенный в именах массивов и возрастах:

@Test
public void givenALinkedMap_whenIteratedWithMapIterator_thenPreservesOrder() {
    OrderedMapIterator<String, Integer> 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. Удаление элементов

Наконец, давайте проверим, как можно удалить элемент по индексу или по объекту:

@Test
public void givenALinkedMap_whenElementRemoved_thenSizeDecrease() {
    LinkedMap<String, Integer> lmap 
      = (LinkedMap<String, Integer>) 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, который можно создать из любой карты с помощью статического метода ListOrderedMap.decorate(Map map).

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

Обе реализации также предоставляют три метода, которые находятся вне интерфейса OrderedMap:

    asList() — получает список типа List\u003cK\u003e (где K — тип ключей), сохраняя порядок карты get(int index) — получает элемент с индексом позиции в отличие от метода get(Object o), предоставленного в интерфейсе indexOf(Object o) — получает индекс объекта o в упорядоченной карте

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

@Test
public void givenALinkedMap_whenConvertedToList_thenMatchesKeySet() {
    LinkedMap<String, Integer> lmap 
      = (LinkedMap<String, Integer>) this.runnersLinkedMap;
    
    List<String> listKeys = new ArrayList<>();
    listKeys.addAll(this.runnersLinkedMap.keySet());
    List<String> linkedMap = lmap.asList();
 
    assertEquals(listKeys, linkedMap);
}

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

@Test
public void givenALinkedMap_whenSearchByIndexIsUsed_thenMatchesConstantArray() {
    LinkedMap<String, Integer> lmap 
      = (LinkedMap<String, Integer>) 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, его основные методы и реализации.

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

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

Next »

Apache Commons Collections BidiMap

« Previous

Apache Commons Collections SetUtils