Apache Commons Collections Bag

1. Introduction

In this quick article, we’ll focus on how to use the Apache’s Bag collection.

2. Maven Dependency

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.1</version>
</dependency>

3. Bags vs Collections

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

3.1. Violations of the Collection Contract

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

4. Bag Implementations

Let’s now explore the various implementations of the Bag interface – within Apache’s collections library.

4.1. HashBag

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

4.2. TreeBag

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

4.3. SynchronizedSortedBag

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.

5. Conclusion

In this short tutorial, we’ve learned about the Bag interface and its various implementations.

As always, the code for this article can be found over on GitHub.

Related posts:

Setting a Request Timeout for a Spring REST API
Java Program to Implement Regular Falsi Algorithm
Hướng dẫn Java Design Pattern – Null Object
Java Program to Represent Graph Using Linked List
Tìm hiểu về xác thực và phân quyền trong ứng dụng
Tạo ứng dụng Java RESTful Client với thư viện OkHttp
The DAO with JPA and Spring
Hướng dẫn sử dụng Lớp FilePermission trong java
Java Program to Implement Horner Algorithm
Giới thiệu thư viện Apache Commons Chain
Java Program to Perform Insertion in a 2 Dimension K-D Tree
Basic Authentication with the RestTemplate
Spring Boot - Admin Client
Hướng dẫn Java Design Pattern – Adapter
Mockito and JUnit 5 – Using ExtendWith
Java Program to Implement Vector API
Java Program to Implement Hash Tree
Hướng dẫn Java Design Pattern – DAO
Java Program to Find the Shortest Path Between Two Vertices Using Dijkstra’s Algorithm
Java Program to Implement Hash Tables
Java Program to Implement Pairing Heap
Java Program to Check whether Directed Graph is Connected using BFS
Java Program to Implement the Monoalphabetic Cypher
Java Program to Construct an Expression Tree for an Postfix Expression
Java Program to Implement Pollard Rho Algorithm
Java Program to Implement Quick sort
Java Program to Implement Gift Wrapping Algorithm in Two Dimensions
Java Program to Create a Minimal Set of All Edges Whose Addition will Convert it to a Strongly Conne...
Hướng dẫn Java Design Pattern – MVC
Java Program to Perform Arithmetic Operations on Numbers of Size
Java Program to Find kth Largest Element in a Sequence
Flattening Nested Collections in Java