Коллекции 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.