Apache Commons Bag简介
1.简介
在这篇快速文章中,我们将重点介绍如何使用 Apache 的Bag集合。
2. Maven依赖
在开始之前,我们需要从Maven Central 导入最新的依赖项:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
3. Bag与Collection
简而言之,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. 违反Collection
在阅读Bag的 API 文档时,我们可能会注意到某些方法被标记为违反标准 Java 的 Collection。
例如,当我们使用 Java 集合中的add() API 时,即使项目已经在集合中,我们也会收到true :
Collection<Integer> collection = new ArrayList<>();
collection.add(1);
assertThat(collection.add(1), is(true));
当我们添加集合中已经可用的元素时,来自Bag实现的相同 API将返回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 的集合库中探索Bag接口的各种实现。
4.1. HashBag
我们可以添加一个元素并指示 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
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. SynchronizedSortedBag
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所做的事情。