1. 概述
在本篇文章中,我们将介绍如何使用 Guava 来简化 Java 中 Set 的操作。Guava 提供了大量实用的工具方法,让集合操作更加优雅高效。
先来看一个简单的例子:使用 Guava 创建一个 HashSet
,无需显式使用 new
关键字:
Set<String> aNewSet = Sets.newHashSet();
✅ 简单粗暴,一行搞定。
2. 集合并集(Union)
使用 Sets.union()
可以轻松获取两个集合的并集:
@Test
public void whenCalculatingUnionOfSets_thenCorrect() {
Set<Character> first = ImmutableSet.of('a', 'b', 'c');
Set<Character> second = ImmutableSet.of('b', 'c', 'd');
Set<Character> union = Sets.union(first, second);
assertThat(union, containsInAnyOrder('a', 'b', 'c', 'd'));
}
并集操作会返回两个集合中所有不重复的元素组成的集合。
3. 笛卡尔积(Cartesian Product)
使用 Sets.cartesianProduct()
可以计算两个集合的笛卡尔积:
@Test
public void whenCalculatingCartesianProductOfSets_thenCorrect() {
Set<Character> first = ImmutableSet.of('a', 'b');
Set<Character> second = ImmutableSet.of('c', 'd');
Set<List<Character>> result =
Sets.cartesianProduct(ImmutableList.of(first, second));
Function<List<Character>, String> func =
new Function<List<Character>, String>() {
public String apply(List<Character> input) {
return Joiner.on(" ").join(input);
}
};
Iterable<String> joined = Iterables.transform(result, func);
assertThat(joined, containsInAnyOrder("a c", "a d", "b c", "b d"));
}
⚠️ 注意:笛卡尔积的结果是 Set<List<T>>
类型,为了方便测试,这里使用 Function
和 Joiner
将其转换为字符串形式。
4. 集合交集(Intersection)
使用 Sets.intersection()
可以获取两个集合的交集:
@Test
public void whenCalculatingSetIntersection_thenCorrect() {
Set<Character> first = ImmutableSet.of('a', 'b', 'c');
Set<Character> second = ImmutableSet.of('b', 'c', 'd');
Set<Character> intersection = Sets.intersection(first, second);
assertThat(intersection, containsInAnyOrder('b', 'c'));
}
交集操作返回两个集合中都存在的元素。
5. 对称差集(Symmetric Difference)
对称差集是指两个集合中只存在于其中一个集合的元素:
@Test
public void whenCalculatingSetSymmetricDifference_thenCorrect() {
Set<Character> first = ImmutableSet.of('a', 'b', 'c');
Set<Character> second = ImmutableSet.of('b', 'c', 'd');
Set<Character> intersection = Sets.symmetricDifference(first, second);
assertThat(intersection, containsInAnyOrder('a', 'd'));
}
也就是说,排除两个集合的交集,剩下的就是对称差集。
6. 幂集(Power Set)
使用 Sets.powerSet()
可以计算一个集合的幂集,即该集合的所有子集(包括空集和自身):
@Test
public void whenCalculatingPowerSet_thenCorrect() {
Set<Character> chars = ImmutableSet.of('a', 'b');
Set<Set<Character>> result = Sets.powerSet(chars);
Set<Character> empty = ImmutableSet.<Character> builder().build();
Set<Character> a = ImmutableSet.of('a');
Set<Character> b = ImmutableSet.of('b');
Set<Character> aB = ImmutableSet.of('a', 'b');
assertThat(result, contains(empty, a, b, aB));
}
幂集在组合数学和算法中经常使用,Guava 提供了非常直观的 API 支持。
7. 连续集合(ContiguousSet)
ContiguousSet
是一个有序的、连续的整数集合。例如,表示区间 [10, 30]
的所有整数:
@Test
public void whenCreatingRangeOfIntegersSet_thenCreated() {
int start = 10;
int end = 30;
ContiguousSet<Integer> set = ContiguousSet.create(
Range.closed(start, end), DiscreteDomain.integers());
assertEquals(21, set.size());
assertEquals(10, set.first().intValue());
assertEquals(30, set.last().intValue());
}
虽然 Java 原生可以用 TreeSet
实现类似功能,但 ContiguousSet
的语义更加清晰,特别适合处理连续整数范围。
8. 范围集合(RangeSet)
RangeSet
用于表示一组不连续但非空的区间,并支持自动合并重叠区间:
@Test
public void whenUsingRangeSet_thenCorrect() {
RangeSet<Integer> rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closed(1, 10));
rangeSet.add(Range.closed(12, 15));
assertEquals(2, rangeSet.asRanges().size());
rangeSet.add(Range.closed(10, 12));
assertTrue(rangeSet.encloses(Range.closed(1, 15)));
assertEquals(1, rangeSet.asRanges().size());
}
解释一下这个例子:
- 先添加两个不连续的区间:
[1, 10]
和[12, 15]
- 再添加一个连接它们的区间:
[10, 12]
- 最终
RangeSet
自动合并为一个大区间:[1, 15]
✅ 非常适合处理区间合并、范围判断等场景。
9. 多重集合(MultiSet)
与普通 Set 不同,Multiset
允许重复元素,并记录每个元素出现的次数:
@Test
public void whenInsertDuplicatesInMultiSet_thenInserted() {
Multiset<String> names = HashMultiset.create();
names.add("John");
names.add("Adam", 3);
names.add("John");
assertEquals(2, names.count("John"));
names.remove("John");
assertEquals(1, names.count("John"));
assertEquals(3, names.count("Adam"));
names.remove("Adam", 2);
assertEquals(1, names.count("Adam"));
}
Multiset
是统计元素频次的利器,比如词频统计、排行榜等场景。
10. 获取 MultiSet 中出现次数最多的 N 个元素
下面是一个更实用的例子:获取 Multiset
中出现次数最多的前 N 个元素:
@Test
public void whenGetTopOcurringElementsWithMultiSet_thenCorrect() {
Multiset<String> names = HashMultiset.create();
names.add("John");
names.add("Adam", 5);
names.add("Jane");
names.add("Tom", 2);
Set<String> sorted = Multisets.copyHighestCountFirst(names).elementSet();
List<String> sortedAsList = Lists.newArrayList(sorted);
assertEquals("Adam", sortedAsList.get(0));
assertEquals("Tom", sortedAsList.get(1));
}
使用 Multisets.copyHighestCountFirst()
可以按出现次数从高到低排序,非常方便。
11. 总结
本文介绍了 Guava 中 Sets
工具类的常用方法和实际应用场景,包括:
- 并集、交集、差集、对称差集
- 笛卡尔积与幂集
- 连续集合与范围集合
- 多重集合及其排序统计
这些工具极大提升了 Java 集合的操作效率和可读性。
📌 所有示例代码均可在 GitHub 项目 中找到,基于 Eclipse 构建,导入即可运行。