下面我将介绍几种最常用和最推荐的遍历 HashSet 的方法,并提供详细的代码示例和解释。

准备工作:创建一个示例 HashSet
我们创建一个 HashSet 并添加一些元素,以便在后续的示例中使用。
import java.util.HashSet;
import java.util.Set;
public class HashSetIterationExample {
public static void main(String[] args) {
// 创建一个 HashSet 并添加一些水果
Set<String> fruits = new HashSet<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
fruits.add("Grape");
// 重复添加 "Apple",但 Set 会保证唯一性
fruits.add("Apple");
System.out.println("原始 HashSet 内容: " + fruits);
// 注意:输出顺序可能与添加顺序不同, [Orange, Apple, Grape, Banana]
}
}
使用增强 for 循环 (For-Each Loop)
这是最常用、最简洁、最推荐的方式,它适用于任何实现了 Iterable 接口的集合,包括 HashSet。
语法:
for (Type element : set) {
// 处理 element
}
示例:

System.out.println("\n--- 使用增强 for 循环遍历 ---");
for (String fruit : fruits) {
System.out.println("水果: " + fruit);
}
优点:
- 代码简洁易读:语法非常清晰,没有冗余的代码。
- 性能好:对于
HashSet其内部迭代器的效率很高。 - 安全:在遍历过程中,如果尝试调用
set.remove()方法,会抛出ConcurrentModificationException异常,这可以防止在迭代时意外修改集合,保证了遍历的安全性。
缺点:
- 无法获取索引:如果你需要在遍历时获取元素的索引,这种方法不适用。
- 不能在遍历中安全地删除元素:如上所述,直接调用
remove()会抛出异常,如果需要在遍历时删除元素,应该使用方法三或方法四。
使用迭代器 (Iterator)
这是最传统、最底层的方式,也是 Java Collections Framework 提供的标准遍历机制,它提供了在遍历过程中安全地删除元素的能力。
语法:

Iterator<Type> iterator = set.iterator();
while (iterator.hasNext()) {
Type element = iterator.next();
// 处理 element
}
示例:
System.out.println("\n--- 使用 Iterator 遍历 ---");
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
String fruit = iterator.next();
System.out.println("水果: " + fruit);
}
优点:
- 功能强大:可以安全地在遍历过程中删除元素(通过调用
iterator.remove())。 - 通用性:是所有集合类通用的遍历方式。
缺点:
- 代码稍显冗长:相比增强 for 循环,需要多写几行代码。
在遍历中安全地删除元素
Iterator 的一个核心优势是它的 remove() 方法,这个方法会删除上次调用 next() 方法返回的元素。
示例:删除长度小于 5 的水果
System.out.println("\n--- 使用 Iterator 在遍历中安全删除元素 ---");
// 注意:这里我们创建一个新的 HashSet 来演示,避免混淆
Set<String> fruitsForRemoval = new HashSet<>(fruits);
Iterator<String> removalIterator = fruitsForRemoval.iterator();
while (removalIterator.hasNext()) {
String fruit = removalIterator.next();
if (fruit.length() < 5) {
removalIterator.remove(); // 安全地删除当前元素
System.out.println("已删除: " + fruit);
}
}
System.out.println("删除后的 HashSet 内容: " + fruitsForRemoval);
错误示范 (会抛出异常):
// for (String fruit : fruitsForRemoval) {
// if (fruit.length() < 5) {
// fruitsForRemoval.remove(fruit); // ConcurrentModificationException
// }
// }
使用 Java 8+ 的 Stream API (forEach)
如果你使用的是 Java 8 或更高版本,可以使用 Stream API 来遍历集合,这种方式非常适合进行函数式编程风格的操作,如过滤、映射等。
语法:
set.stream().forEach(element -> {
// 处理 element
});
示例:
System.out.println("\n--- 使用 Java 8 Stream API 的 forEach 遍历 ---");
fruits.stream().forEach(fruit -> System.out.println("水果: " + fruit));
你也可以使用方法引用(Method Reference)让代码更简洁:
fruits.forEach(System.out::println);
优点:
- 函数式编程风格:非常适合与链式操作(如
filter,map,collect)结合使用。 - 并行处理:可以轻松地通过
parallelStream()实现并行遍历,以提高大数据量下的处理速度。
缺点:
- 性能开销:对于简单的遍历,创建 Stream 会带来轻微的性能开销。
- 不能直接删除元素:
forEach内部也是一个“外部迭代器”,直接调用集合的remove()方法同样会抛出ConcurrentModificationException,如果你想在 Stream 操作中删除元素,通常需要先收集到一个新的集合中。
使用 Java 8+ 的 removeIf
如果你需要在遍历时根据条件删除元素,removeIf 是最直接、最优雅的方法,它内部就是使用迭代器实现的,所以是线程安全的。
语法:
set.removeIf(element -> condition);
示例:删除所有以 "A" 开头的水果(不区分大小写)
System.out.println("\n--- 使用 Java 8 removeIf 删除元素 ---");
System.out.println("删除前的内容: " + fruits);
fruits.removeIf(fruit -> fruit.toUpperCase().startsWith("A"));
System.out.println("删除以 'A' 开头的水果后: " + fruits);
优点:
- 代码极其简洁:一行代码就能完成条件删除。
- 安全高效:内部使用迭代器,保证了遍历和删除的安全性。
缺点:
- 功能单一:仅用于删除元素,不能用于其他处理。
总结与选择建议
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 增强 for 循环 | 简洁、易读、性能好 | 无法获取索引,遍历时不能安全删除 | 绝大多数日常遍历场景,首选。 |
| Iterator | 功能强大,可安全删除元素 | 代码稍显冗长 | 需要在遍历过程中安全地删除元素时。 |
| Stream API | 函数式风格,支持并行和链式操作 | 有性能开销,遍历时不能直接删除 | 需要进行复杂的函数式操作(过滤、映射等)或并行处理时。 |
| removeIf | 代码极其简洁,专为条件删除设计 | 功能单一 | 仅需根据条件批量删除元素时。 |
- 只是想简单地读取每一个元素:用 增强 for 循环。
- 想在读的时候顺便删掉一些元素:用 Iterator 或者 Java 8+ 的 removeIf。
- 想对元素进行复杂的处理(比如筛选、转换):用 Stream API。
