iterable接口仅声明“可被遍历”,不定义遍历逻辑,其核心是iterator()方法;for-each编译为调用该方法获取iterator后循环hasnext()/next();iterator.remove()是可选操作,是否支持取决于数据源是否允许边遍历边修改。

Iterable 接口只负责“能被遍历”,不负责“怎么遍历”
Java 中 Iterable 是一个函数式接口,核心就一个方法:iterator()。它不定义遍历逻辑,只承诺“我能给你一个 Iterator”。比如 ArrayList 实现了 Iterable,但真正移动指针、返回元素的是它内部返回的 ArrayList.Itr 对象。
常见误解是认为实现了 Iterable 就自动支持 for-each —— 实际上 for-each 编译后就是调用 iterator().hasNext() 和 iterator().next(),所以关键在 iterator() 返回的对象是否符合契约。
- 自定义类想支持 for-each,必须实现
Iterable<t></t>,且iterator()返回的Iterator<t></t>要正确维护状态(如游标位置) - 如果
iterator()每次都返回新实例(如 new ArrayList().iterator()),多次遍历互不影响;若返回同一个对象(如单例迭代器),第二次调用hasNext()很可能直接返回false -
Iterable可被多次调用iterator(),但Iterator通常是一次性消费的:遍历完或中途抛异常后,再调next()多数会抛NoSuchElementException
Iterator 的 remove() 方法为什么是“可选操作”?
Iterator.remove() 在 API 文档里明确标注为“optional operation”,意思是实现类可以抛 UnsupportedOperationException。比如 Arrays.asList(...).iterator() 返回的迭代器支持 remove(),但 Stream.of(...).iterator() 返回的就不支持。
根本原因在于数据源是否允许“边遍历边修改”。底层是数组副本、不可变集合或流式生成器时,删除没有对应的数据结构支撑。
- 调用前务必查 Javadoc 或测试 —— 不要假设所有
Iterator都能删 -
ConcurrentHashMap的迭代器不支持remove(),而HashMap的可以,这是由并发安全机制决定的 - 自己实现
Iterator时,如果不想支持删除,直接 thrownew UnsupportedOperationException("remove not supported"),比留空更清晰
for-each 循环底层到底做了什么?
Java 编译器把 for (String s : list) 翻译成三步:获取迭代器 → 检查是否有下一个 → 取值并推进。等价于:
Iterator<string> $iter = list.iterator();
while ($iter.hasNext()) {
String s = $iter.next();
// your code
}</string>
这意味着:一旦在循环体里手动调了 $iter.next() 或 $iter.remove(),就会跳过下一个元素或引发 IllegalStateException(如果迭代器不允许并发修改)。
- 禁止在 for-each 循环里调用外部持有的
Iterator方法,哪怕你刚 cast 出来也不行 - 需要边遍历边删元素?用显式
Iterator并只调它的remove()—— 这是唯一安全的方式 - 泛型擦除后,
Iterator<string></string>和Iterator<integer></integer>运行时都是Iterator,类型检查全靠编译期,所以写错泛型参数不会报运行时错,但会出ClassCastException
Stream.iterator() 和 Collection.iterator() 的行为差异
Collection.iterator() 总是返回一个“快照式”迭代器:它基于当前集合状态构建,后续集合变化不影响已获取的迭代器(除非是并发集合)。而 Stream.iterator() 是惰性的,且只能消费一次;一旦调过 next(),再次调用会抛 IllegalStateException。
更关键的是:Stream 的迭代器不保证顺序(除非是 sorted() 流),也不反映中间操作(如 filter())的实时结果 —— 它只是把整个流水线“执行一遍”后吐出结果。
-
Stream.iterate(0, i -> i + 1).limit(5).iterator()返回的迭代器,next()五次后第六次必抛异常,不是因为没元素,而是设计如此 - 不要对同一个
Stream多次调iterator()—— Stream 不能复用,第二次调会抛IllegalStateException - 如果需要多次遍历,要么重新创建 Stream,要么先收集到
List再调iterator()
Iterator 实例,或者以为 Iterable 子类自动继承了某种遍历策略。










