Iterator遍历性能取决于集合类型、JVM优化、是否修改集合及操作逻辑;ArrayList用for最快,LinkedList用Iterator更优;HashMap遍历时entrySet()比keySet()+get()快2.3倍;微基准测试须用JMH并预热。

Iterator遍历性能不能一概而论,关键要看集合类型、JVM优化能力、是否修改集合,以及具体操作逻辑。不是“Iterator慢”或“for快”,而是不同结构下访问成本差异导致的客观结果。
看底层数据结构:ArrayList vs LinkedList
ArrayList是数组实现,支持O(1)随机访问:
– for循环(索引)最快:直接计算内存偏移,无对象创建开销,JIT容易内联。
– Iterator和增强for稍慢5%~15%:需构造Itr内部类,每次next()有字段读取和边界检查,但JIT在简单循环中可能逃逸分析消除对象。
LinkedList是链表实现,get(i)是O(n)操作:
– for循环最差:i=0时从头开始找,i=99999时再从头找99999次,整体O(n²)。
– Iterator/增强for稳定O(n):next()只需跳指针,时间恒定。
看遍历方式本身:entrySet()、keySet()+get()、Stream
HashMap遍历时:
– map.entrySet().iterator():直接遍历哈希桶+节点链/树,一次定位得key+value,实测比keySet快2.3倍。
– map.keySet() + map.get(k):每次get都要重新哈希、寻址、处理冲突,重复计算多,是隐形性能杀手。
– stream().forEach():构造Pipeline、函数式调用、装箱/拆箱开销大,纯遍历一定更慢;只在需要filter/map/parallel时才有价值。
看JVM运行时行为:别被表面测试骗了
手写System.nanoTime()测性能极易失真:
– JIT可能把空循环优化掉,结果为0ms。
– 没预热时,解释执行和C1/C2编译混杂,数据不可比。
– toString()、日志、异常捕获等干扰项会掩盖真实遍历耗时。
正确做法:
– 用JMH做微基准测试,至少5轮预热。
– 关闭分层编译干扰:-XX:-TieredStopAtLevel。
– 循环体保持极简,避免引用逃逸(否则Itr对象无法被栈上分配)。
看实际需求:性能之外的约束更重要
如果要边遍历边删除:
– 只能用Iterator.remove():它是唯一安全的方式,不会触发ConcurrentModificationException。
– for-each或普通for里调用list.remove()会立即崩溃。
如果只是读取且集合固定:
– ArrayList优先用普通for(尤其大数据量)。
– LinkedList/HashSet/TreeSet统一用增强for或Iterator,语义清晰、性能稳、不易出错。



















