1. 概述
本文将深入探讨 Apache Commons Collections 库中的 SetUtils
工具类。简单来说,这些工具类能帮我们高效处理 Java 中的 Set
数据结构操作。
2. 依赖安装
要在项目中使用 SetUtils
,需在 pom.xml
添加以下依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
如果是 Gradle 项目,在 build.gradle
中添加(确保配置了 mavenCentral()
仓库):
compile 'org.apache.commons:commons-collections4:4.1'
3. 断言集合
predicatedSet()
方法允许定义集合元素的准入条件。它接收一个源 Set
和一个 Predicate
断言。
这个特性在开发第三方库/API 时特别实用,能确保所有元素满足特定条件。⚠️ 注意:当元素验证失败时会抛出 IllegalArgumentException
。
以下代码禁止添加不以 'L' 开头的字符串:
Set<String> validatingSet
= SetUtils.predicatedSet(sourceSet, s -> s.startsWith("L"));
针对 SortedSet
和 NavigableSet
,库还提供了 predicatedSortedSet()
和 predicatedNavigableSet()
方法。
4. 集合的并集、差集与交集
SetUtils
提供了计算集合并集、差集和交集的便捷方法:
4.1 差集计算
difference()
方法接收两个 Set
,返回不可变的 SetUtils.SetView
对象,包含集合 a 中存在但集合 b 中不存在的元素:
Set<Integer> a = new HashSet<>(Arrays.asList(1, 2, 5));
Set<Integer> b = new HashSet<>(Arrays.asList(1, 2));
SetUtils.SetView<Integer> result = SetUtils.difference(a, b);
assertTrue(result.size() == 1 && result.contains(5));
⚠️ 踩坑提示:**对返回的 SetView
执行写操作(如 add()
或 addAll()
)会抛出 UnsupportedOperationException
**。需调用 toSet()
获取可写集合:
Set<Integer> mutableSet = result.toSet();
4.2 并集计算
union()
方法返回两个集合的所有元素(同样返回不可变 SetView
):
Set<Integer> expected = new HashSet<>(Arrays.asList(1, 2, 5));
SetUtils.SetView<Integer> union = SetUtils.union(a, b);
assertTrue(SetUtils.isEqualSet(expected, union));
✅ 技巧:isEqualSet()
是 SetUtils
提供的静态方法,用于高效判断两个集合是否相等。
4.3 交集计算
intersection()
返回两个集合共有的元素:
Set<Integer> expected = new HashSet<>(Arrays.asList(1, 2));
SetUtils.SetView<Integer> intersect = SetUtils.intersection(a, b);
assertTrue(SetUtils.isEqualSet(expected, intersect));
5. 集合元素转换
transformedSet()
方法接收一个 Set
和 Transformer
接口。它基于源集合,使用 Transformer
的 transform()
方法转换每个元素。
转换逻辑在 transform()
中定义,会作用于所有新增元素。以下代码将每个元素乘以 2:
Set<Integer> a = SetUtils.transformedSet(new HashSet<>(), e -> e * 2 );
a.add(2);
assertEquals(a.toArray()[0], 4);
这个方法非常实用,甚至可用于类型转换(如 String → Integer),但需确保输出类型是输入类型的子类。
对于 SortedSet
或 NavigableSet
,可使用 transformedSortedSet()
或 transformedNavigableSet()
。
⚠️ 重要:向 transformedSet()
传递非空集合时,已有元素不会被转换。若需转换已有元素及后续新增元素,应使用 TransformedSet.transformedSet()
:
Set<Integer> source = new HashSet<>(Arrays.asList(1));
Set<Integer> newSet = TransformedSet.transformedSet(source, e -> e * 2);
assertEquals(newSet.toArray()[0], 2);
assertEquals(source.toArray()[0], 2);
6. 集合对称差
disjunction()
方法计算两个集合的对称差(仅存在于其中一个集合的元素):
Set<Integer> a = new HashSet<>(Arrays.asList(1, 2, 5));
Set<Integer> b = new HashSet<>(Arrays.asList(1, 2, 3));
SetUtils.SetView<Integer> result = SetUtils.disjunction(a, b);
assertTrue(
result.toSet().contains(5) && result.toSet().contains(3));
7. 其他实用方法
SetUtils
还提供了一系列简化集合操作的实用方法:
✅ 线程安全集合
synchronizedSet()
/synchronizedSortedSet()
:获取线程安全集合- ⚠️ 注意:必须手动同步返回集合的迭代器,否则可能导致非确定性行为
✅ 不可变集合
unmodifiableSet()
:获取只读集合(修改操作抛出UnsupportedOperationException
)emptySet()
:返回类型安全的不可变空集合
✅ 空值处理
emptyIfNull()
:接收可空Set
,若为 null 返回空只读集合,否则返回原集合
✅ 有序集合
orderedSet()
:返回保持插入顺序的Set
✅ 哈希工具
hashCodeForSet()
:为集合生成哈希码(相同元素的集合哈希码相同)newIdentityHashSet()
:返回使用==
而非equals()
比较元素的HashSet
(⚠️ 使用前需了解其陷阱)
8. 总结
本文深入剖析了 SetUtils
工具类。其提供的静态方法让集合操作变得简单高效,显著提升开发效率。所有示例代码可在 GitHub 获取,官方文档见 此处。