Apache Commons Collections Bag – 阿帕奇共享资源收集袋

最后修改: 2017年 9月 28日

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:

在开始之前,我们需要从Maven Central导入最新的依赖项。


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:

例如,当我们从一个Java集合中使用add() API时,我们会收到true,即使该项目已经在集合中。

Collection<Integer> collection = new ArrayList<>();
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<>();
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:

为了解决这些问题,Apache Collections库提供了一个名为CollectionBag.的装饰器,我们可以使用它来使我们的袋子集合符合JavaCollection契约。

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

    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

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

    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.

我们可以使用API的组合–Collections.synchronizedSortedMap() TreeMap–来模拟我们在这里用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.


Next »

Apache Commons Collections SetUtils