
Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:
Once the early-adopter seats are all used, the price will go up and stay at $33/year.
Last updated: January 5, 2024
In this quick article, we’ll focus on how to use the Apache’s Bag collection.
Before we start, we need to import the latest dependencies from Maven Central:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.5.0-M2</version>
</dependency>
Simply put, Bag is a collection that allows storing multiple items along with their repetition count:
public void whenAdded_thenCountIsKept() {
Bag<Integer> bag = new HashBag<>(
Arrays.asList(1, 2, 3, 3, 3, 1, 4));
assertThat(2, equalTo(bag.getCount(1)));
}
While reading Bag‘s API documentation, we may notice that some methods are marked as violating the standard Java’s Collection contract.
For example, when we use an add() API from a Java collection, we receive true even if the item is already in the collection:
Collection<Integer> collection = new ArrayList<>();
collection.add(1);
assertThat(collection.add(1), is(true));
The same API from a Bag implementation will return a false when we add an element which is already available in the collection:
Bag<Integer> bag = new HashBag<>();
bag.add(1);
assertThat(bag.add(1), is(not(true)));
To resolve these issues, Apache Collections’ library provides a decorator called the CollectionBag. We can use this to make our bag collections compliant with the Java Collection contract:
public void whenBagAddAPILikeCollectionAPI_thenTrue() {
Bag<Integer> bag = CollectionBag.collectionBag(new HashBag<>());
bag.add(1);
assertThat(bag.add(1), is((true)));
}
Let’s now explore the various implementations of the Bag interface – within Apache’s collections library.
We can add an element and instruct the API on the number of copies this element should have in our bag collection:
public void givenAdd_whenCountOfElementsDefined_thenCountAreAdded() {
Bag<Integer> bag = new HashBag<>();
bag.add(1, 5); // adding 1 five times
assertThat(5, equalTo(bag.getCount(1)));
}
We can also delete a specific number of copies or every instance of an element from our bag:
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)));
}
The TreeBag implementation works like any other tree, additionally maintaining Bag semantics.
We can naturally sort an array of integers with a TreeBag and then query the number of instances each individual element has within the collection:
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));
}
The TreeBag implements a SortedBag interface, all implementations of this interface can use the decorator CollectionSortedBag to comply with the Java Collections contract:
public void whenTreeAddAPILikeCollectionAPI_thenTrue() {
SortedBag<Integer> bag
= CollectionSortedBag.collectionSortedBag(new TreeBag<>());
bag.add(1);
assertThat(bag.add(1), is((true)));
}
Another widely used implementation of Bag is the SynchronizedSortedBag. Precisely, this is a synchronized decorator of a SortedBag implementation.
We can use this decorator with our TreeBag (an implementation of SortedBag) from the previous section to synchronize access to our bag:
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));
}
We can use a combination of APIs – Collections.synchronizedSortedMap() and TreeMap – to simulate what we did here with SynchronizedSortedBag.
In this short tutorial, we’ve learned about the Bag interface and its various implementations.