在Java编程中,Set是一种不允许重复元素的集合接口,它继承自Collection接口,遍历Set集合是日常开发中常见的操作,掌握多种遍历方法不仅能提高代码效率,还能根据不同场景选择最优解,本文将详细介绍Java中遍历Set的多种方式,包括其原理、适用场景及代码示例。

使用增强for循环(for-each)
增强for循环是Java 1.5引入的特性,专门用于遍历集合和数组,其底层基于Iterator实现,语法简洁且不易出错,是遍历Set最常用的方式之一。
代码示例:
Set<String> set = new HashSet<>();
set.add("Java");
set.add("Python");
set.add("C++");
for (String language : set) {
System.out.println(language);
}
优点:代码可读性高,无需关心索引或迭代器细节。
注意事项:遍历过程中不能直接调用Set的remove()方法删除元素,否则会抛出ConcurrentModificationException,若需删除元素,应使用Iterator的remove()方法。
使用Iterator迭代器
Iterator是Java集合框架中的迭代器接口,专门用于安全遍历集合元素,它提供了hasNext()、next()和remove()三个核心方法,支持在遍历时动态修改集合。
代码示例:
Set<Integer> set = new TreeSet<>();
set.add(10);
set.add(20);
set.add(30);
Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()) {
Integer num = iterator.next();
if (num == 20) {
iterator.remove(); // 安全删除元素
}
}
优点:支持安全删除元素,适用于需要动态修改集合的场景。
适用场景:当遍历过程中需要增删元素时,Iterator是唯一可靠的选择。
使用Java 8 Stream API
Java 8引入的Stream为集合操作提供了函数式编程风格,通过Stream可以优雅地遍历并处理Set元素。
代码示例:

Set<Double> set = new HashSet<>(); set.add(3.14); set.add(2.71); set.add(1.618); // 遍历并打印 set.stream().forEach(System.out::println); // 过滤后遍历 set.stream() .filter(num -> num > 2.0) .forEach(System.out::println);
优点:支持链式操作,可结合filter、map等中间方法实现复杂逻辑,代码简洁且功能强大。
注意事项:Stream遍历是惰性求值的,终端操作(如forEach)触发后才会执行。
使用Lambda表达式
结合forEach方法和Lambda表达式,可以进一步简化遍历代码,这种方式特别适合函数式编程风格的场景。
代码示例:
Set<Character> set = new HashSet<>();
set.add('A');
set.add('B');
set.add('C');
// 使用Lambda表达式
set.forEach(c -> System.out.println(c));
// 方法引用简化
set.forEach(System.out::println);
优点:代码极简,可读性强,适合简单的遍历操作。
局限性:遍历过程中无法直接修改集合(如删除元素)。
使用List转换后遍历
虽然Set本身不支持索引遍历,但可以通过转换为List后使用普通for循环遍历,这种方式在需要通过索引访问元素时较为实用。
代码示例:
Set<String> set = new LinkedHashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Orange");
List<String> list = new ArrayList<>(set);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
优点:支持通过索引随机访问元素,适用于需要根据索引位置进行特殊处理的场景。
缺点:需要额外空间转换List,效率低于直接遍历Set。

不同遍历方式的性能对比
- 增强for循环:性能与Iterator相当,适合大多数场景。
- Iterator:遍历时删除元素的开销稍大,但安全性最高。
- Stream API:在并行流(parallelStream)场景下性能优势明显,但单线程遍历时可能存在额外开销。
- Lambda表达式:底层与Stream类似,可读性优先于性能。
- List转换:增加了转换成本,不推荐仅为了遍历而转换。
遍历时的注意事项
- 线程安全:若Set在多线程环境下被修改,需使用
Collections.synchronizedSet()或ConcurrentHashMap.NewKeySet()等线程安全实现类。 - 修改集合:除Iterator和Stream的remove()方法外,其他遍历方式直接修改集合均会抛出异常。
- 遍历顺序:HashSet的遍历顺序不确定,若需有序遍历,应使用LinkedHashSet或TreeSet。
Java中遍历Set的方法多样,开发者应根据实际需求选择合适的遍历方式:
- 日常遍历:优先使用增强for循环或Lambda表达式,代码简洁高效。
- 动态修改:必须使用Iterator或Stream API的remove()方法。
- 复杂操作:Stream API能提供最灵活的函数式处理能力。
- 索引需求:通过List转换实现,但需权衡性能开销。
掌握这些遍历方法,并结合集合的特性与场景需求,可以写出更高效、更健壮的Java代码。


















