Menu

Java HashSet:唯一值、成员检查与集合运算

如何用 Java 的 HashSet 存放唯一值的集合:add、contains、remove,给列表去重,以及用并集、交集和差集组合集合。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

Set 存储唯一值

HashSet(来自 java.util)是一种集合,每个值最多只保存一次。它不像 HashMap 那样有键和值配对,只是一堆互不相同的元素。它的全部职责就是快速回答一个问题:“这个东西在不在里面?”

它只有一个类型参数 <ElementType>。和 ArrayList、HashMap 一样,通常把变量声明为 Set 接口类型,再构造一个 HashSet。

add 会告诉你值是不是新的

add 不只是存储值,它还会返回一个 boolean,告诉你集合是否真的发生了变化。添加一个已经存在的值会返回 false,集合保持不变。

这个返回值非常有用:if (!seen.add(x)) { /* x is a repeat */ } 让你在遍历的同时用一行代码检测出重复项。

给列表去重

因为集合会拒绝重复值,给一个集合类去重最快的方法就是把它整个倒进 Set 里。HashSet 的构造函数接受任何其他集合:

这是初学者用到 Set 最常见的原因。只是要知道,这样转一圈会丢失原来的顺序;如果顺序很重要,请用 LinkedHashSet(下文会讲)。

contains、remove 和 size

日常操作和其他集合类似:

相比 ArrayList,最大的优势在于 contains。列表必须逐个检查每个元素才能回答(O(n));HashSet 几乎能直接找到答案(大约 O(1))。当你发现自己在循环里调用 list.contains(...) 时,通常就该换成 Set 了。

集合运算:并集、交集、差集

Set 的长处在于组合使用。只要分清每个方法对应哪种运算,读起来就像大白话:

关键陷阱:addAll、retainAll 和 removeAll 会修改调用它们的那个集合。所以每个例子都先把 a 复制到一个新的 HashSet 里,否则你会毁掉原来的集合。每个结果都要新建一个集合。

HashSet 不保证顺序

和 HashMap 一样,HashSet 对遍历顺序不做任何保证,每次运行的顺序都可能不同。如果你需要可预测的顺序:

  • LinkedHashSet 保留插入顺序,也就是你添加元素的顺序。
  • TreeSet 让元素按自然顺序(或你提供的 Comparator)排序。

三者都实现了 Set 接口,所以在它们之间切换只需改一行构造函数。

元素必须可哈希

HashSet 底层由 HashMap 支撑,所以规则相同:它通过哈希来定位元素,这意味着元素的 hashCode() 和 equals() 必须保持一致。String 和 Integer 等内置类型已经正确实现了这一点,所以上面重复的 "java" 字符串能被正确合并。如果你存放的是自己的类的实例,就要同时重写 equals 和 hashCode,否则两个在含义上“相等”的对象会被当成不同的对象,contains 和去重都会悄无声息地失效。

下一篇:遍历集合

你已经认识了三个最常用的集合:ArrayList、HashMap 和 HashSet。它们的遍历方式各有不同,还有一些不太明显的陷阱(比如在遍历集合时修改它)。下一篇会把这些串起来,讲解如何用 for-each 循环、迭代器和 forEach 干净地遍历集合。

常见问题

Java 中如何创建 HashSet?

用一个类型参数(元素类型)声明它,然后调用构造函数:Set<String> tags = new HashSet<>();。用 tags.add("java"); 添加值,用 tags.contains("java"); 检查是否存在。需要导入 java.util.HashSet 和 java.util.Set。

Java 中 HashSet 和 ArrayList 有什么区别?

ArrayList 按插入顺序保存你添加的每个元素(包括重复的),并按位置索引。HashSet 只存储唯一值,不保证顺序,没有索引,它的 contains 检查大致是常数时间,而不用扫描整个列表。当你关心唯一性或快速判断是否存在,而不关心位置时,就用 HashSet。

Java 中如何给列表去重?

把列表传给 HashSet 的构造函数:Set<String> unique = new HashSet<>(list);。集合会自动丢弃重复的值。如果你需要再变回列表(并且不在乎丢失顺序),再包一层:new ArrayList<>(unique)。如果想保留原来的顺序,就改用 LinkedHashSet。

Coddy 编程语言插图

和 Coddy 一起学编程

开始