HashSet遍历无序且不支持下标访问,与ArrayList根本不同;需有序用LinkedHashSet,需排序应转List或Stream处理,遍历时删除元素必须用Iterator.remove()。

HashSet 不能保证遍历顺序,且不支持下标访问 —— 这是它和 ArrayList 最根本的区别。如果你只是想“把每个元素拿出来用一遍”,直接用增强 for 或迭代器即可;但若隐含了“需要有序”“要跳过某些元素”“要边遍历边删”等需求,就得特别小心。
用增强 for 循环最简单,但不能删元素
这是日常遍历时最常用的方式,写法简洁,语义清晰:
HashSetset = new HashSet<>(); set.add("apple"); set.add("banana"); set.add("cherry"); for (String item : set) { System.out.println(item); // 输出顺序不确定,可能是 banana, apple, cherry }
⚠️ 注意:循环体内绝对不要调用 set.remove(item),否则会抛 ConcurrentModificationException。HashSet 的迭代器是“快速失败”(fail-fast)的,结构一变就立刻报错。
要用迭代器删除元素,必须用 iterator.remove()
如果逻辑确实需要在遍历时动态剔除某些元素(比如过滤掉空字符串),只能走 Iterator 显式路径:
立即学习“Java免费学习笔记(深入)”;
Iteratorit = set.iterator(); while (it.hasNext()) { String s = it.next(); if (s == null || s.trim().isEmpty()) { it.remove(); // ✅ 唯一安全的删除方式 } }
-
it.remove()是迭代器自己的方法,它会同步更新内部的modCount,避免异常 - 不能写成
set.remove(s),哪怕你刚从it.next()拿到这个s - 每个
it.next()后最多调用一次it.remove(),重复调用会抛IllegalStateException
想按插入顺序遍历?换 LinkedHashSet
标准 HashSet 底层是哈希表 + 链表(JDK 8+ 还可能转红黑树),但链表只用于解决哈希冲突,不维护插入顺序。如果你需要“先加的先出来”,必须显式选型:
SetorderedSet = new LinkedHashSet<>(); orderedSet.add("first"); orderedSet.add("second"); orderedSet.add("third"); for (String s : orderedSet) { System.out.println(s); // 一定输出 first → second → third }
✅ LinkedHashSet 保留插入顺序,遍历性能略低于 HashSet(多维护一条双向链表),内存占用稍高,但绝大多数业务场景可忽略。
需要排序遍历?别硬遍历 HashSet,先转再处理
HashSet 本身无序,也不提供 sort() 方法。如果最终要按字母、数字或自定义规则排序,推荐做法是:把数据抽出来,丢给有序结构处理:
// 方案1:转为 List 后排序 ListsortedList = new ArrayList<>(set); Collections.sort(sortedList); // 方案2:一步到位(Java 8+) List sorted = set.stream() .sorted(String::compareTo) .collect(Collectors.toList()); // 方案3:如果只是临时遍历,用 TreeSet(注意:会去重+排序,但改变原始集合语义) TreeSet treeSet = new TreeSet<>(set); // 自然序
⚠️ 别写 for (int i = 0; i —— HashSet 没有 get(i),编译不过。
真正容易被忽略的是:你以为“遍历 HashSet 就是拿数据”,但实际中往往混着“顺序要求”“并发修改”“空值处理”一起出现。先确认你的场景到底要什么,再选容器和遍历方式,比硬套 for 循环更省调试时间。










