Перейти к основному содержимому

Сумка для коллекций Apache Commons

· 3 мин. чтения

1. Введение

В этой быстрой статье мы сосредоточимся на том, как использовать коллекцию Apache's Bag .

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

Прежде чем мы начнем, нам нужно импортировать последние зависимости из Maven Central :

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

3. Сумки против коллекций

Проще говоря, Bag — это коллекция, которая позволяет хранить несколько элементов вместе с количеством их повторений:

public void whenAdded_thenCountIsKept() {
Bag<Integer> bag = new HashBag<>(
Arrays.asList(1, 2, 3, 3, 3, 1, 4));

assertThat(2, equalTo(bag.getCount(1)));
}

3.1. Нарушения договора инкассо

Читая документацию по API Bag , мы можем заметить, что некоторые методы помечены как нарушающие стандартный контракт Java Collection.

Например, когда мы используем API add() из коллекции Java, мы получаем значение true , даже если элемент уже находится в коллекции:

Collection<Integer> collection = new ArrayList<>();
collection.add(1);
assertThat(collection.add(1), is(true));

Тот же API из реализации Bag вернет false , когда мы добавим элемент, который уже доступен в коллекции:

Bag<Integer> bag = new HashBag<>();
bag.add(1);

assertThat(bag.add(1), is(not(true)));

Для решения этих проблем библиотека Apache Collections предоставляет декоратор CollectionBag. Мы можем использовать это, чтобы наши коллекции сумок соответствовали контракту Java Collection :

public void whenBagAddAPILikeCollectionAPI_thenTrue() {
Bag<Integer> bag = CollectionBag.collectionBag(new HashBag<>());
bag.add(1);

assertThat(bag.add(1), is((true)));
}

4. Реализации сумок

Давайте теперь рассмотрим различные реализации интерфейса Bag в библиотеке коллекций Apache.

4.1. ХэшБэг

Мы можем добавить элемент и указать API, сколько копий этого элемента должно быть в нашей коллекции сумок:

public void givenAdd_whenCountOfElementsDefined_thenCountAreAdded() {
Bag<Integer> bag = new HashBag<>();

bag.add(1, 5); // adding 1 five times

assertThat(5, equalTo(bag.getCount(1)));
}

Мы также можем удалить определенное количество копий или каждый экземпляр элемента из нашей папки:

public void givenMultipleCopies_whenRemove_allAreRemoved() {
Bag<Integer> bag = new HashBag<>(
Arrays.asList(1, 2, 3, 3, 3, 1, 4));

bag.remove(3, 1); // remove one element, two still remain
assertThat(2, equalTo(bag.getCount(3)));

bag.remove(1); // remove all
assertThat(0, equalTo(bag.getCount(1)));
}

4.2. ДеревоСумка

Реализация TreeBag работает как любое другое дерево, дополнительно поддерживая семантику Bag .

Мы можем естественным образом отсортировать массив целых чисел с помощью TreeBag , а затем запросить количество экземпляров каждого отдельного элемента в коллекции:

public void givenTree_whenDuplicateElementsAdded_thenSort() {
TreeBag<Integer> bag = new TreeBag<>(Arrays.asList(7, 5,
1, 7, 2, 3, 3, 3, 1, 4, 7));

assertThat(bag.first(), equalTo(1));
assertThat(bag.getCount(bag.first()), equalTo(2));
assertThat(bag.last(), equalTo(7));
assertThat(bag.getCount(bag.last()), equalTo(3));
}

TreeBag реализует интерфейс SortedBag , все реализации этого интерфейса могут использовать декоратор CollectionSortedBag для соответствия контракту Java Collections:

public void whenTreeAddAPILikeCollectionAPI_thenTrue() {
SortedBag<Integer> bag
= CollectionSortedBag.collectionSortedBag(new TreeBag<>());

bag.add(1);

assertThat(bag.add(1), is((true)));
}

4.3. СинхронизированныйSortedBag

Другой широко используемой реализацией Bag является SynchronizedSortedBag . А именно, это синхронизированный декоратор реализации SortedBag .

Мы можем использовать этот декоратор с нашим TreeBag (реализация SortedBag ) из предыдущего раздела, чтобы синхронизировать доступ к нашему мешку:

public void givenSortedBag_whenDuplicateElementsAdded_thenSort() {
SynchronizedSortedBag<Integer> bag = SynchronizedSortedBag
.synchronizedSortedBag(new TreeBag<>(
Arrays.asList(7, 5, 1, 7, 2, 3, 3, 3, 1, 4, 7)));

assertThat(bag.first(), equalTo(1));
assertThat(bag.getCount(bag.first()), equalTo(2));
assertThat(bag.last(), equalTo(7));
assertThat(bag.getCount(bag.last()), equalTo(3));
}

Мы можем использовать комбинацию API — Collections.synchronizedSortedMap() и TreeMap — для имитации того, что мы сделали здесь с SynchronizedSortedBag .

5. Вывод

В этом коротком руководстве мы узнали об интерфейсе Bag и его различных реализациях.

Как всегда, код для этой статьи можно найти на GitHub .