hashset求差集最常用方式是先复制集合再调用removeall(),stream过滤适合不修改原集合的场景,对称差集可用stream.concat合并两方向差集;需注意null、并发及自定义对象的equals/hashcode实现。

HashSet 本身没有直接求差集的内置方法,但可以用 removeAll() 实现:把一个集合复制出来,再移除另一个集合中存在的所有元素。
用 removeAll() 求 A - B(A 中有、B 中没有的元素)
这是最常用也最高效的方式。注意:removeAll() 会**修改调用它的集合**,所以通常要先复制一份。
- 创建副本:用构造函数
new HashSet(setA) - 调用
retainAll(setB)是交集,removeAll(setB)才是差集(A − B) - 确保元素正确重写了
equals()和hashCode(),否则删除可能失效
示例:
Set<string> setA = new HashSet(Arrays.asList("a", "b", "c"));
Set<string> setB = new HashSet(Arrays.asList("b", "c", "d"));
<p>Set<string> diff = new HashSet(setA); // 复制 A
diff.removeAll(setB); // 移除 B 中存在的元素
// 结果:["a"]</string></p></string></string>不想修改原集合?用 stream 过滤(Java 8+)
适合函数式风格或需要链式操作的场景,不会改变原始集合。
- 用
stream().filter()留下不在 setB 中的元素 - 最后用
collect(Collectors.toSet())转回 HashSet - 性能略低于
removeAll()(尤其大数据量),但语义更清晰
示例:
Set<string> diff = setA.stream()
.filter(item -> !setB.contains(item))
.collect(Collectors.toSet());
</string>求对称差集(A Δ B:只在 A 或只在 B 中的元素)
对称差集 = (A − B) ∪ (B − A),即“互斥”的部分。
- 可分两步:先算 A − B,再算 B − A,最后用
addAll()合并 - 更简洁:用
Stream.concat()合并两个流再去重
示例(简洁版):
Set<string> symDiff = Stream.concat(
setA.stream().filter(e -> !setB.contains(e)),
setB.stream().filter(e -> !setA.contains(e))
)
.collect(Collectors.toSet());
// 结果:["a", "d"]
</string>注意事项
实际使用时容易踩坑的地方:
-
null 元素:HashSet 允许一个 null,但
removeAll()遇到 null 会正常处理;stream 过滤需额外判空 -
并发修改:多线程环境下,建议用
ConcurrentHashMap.newKeySet()替代 HashSet -
自定义对象:务必检查
equals()和hashCode()是否逻辑一致,否则差集结果不可靠











