Iterator & Iterable
Collection 系列文章的总目录:
- Collection 体系的三个核心约定
- Sorted & Navigable
- Iterator & Iterable
- Java 中的数组
- ArrayList
- LinkedList
- HashMap
- LinkedHashMap
- TreeMap
- HashSet/LinkedHashSet/TreeSet
增强 for 循环:
Set<Integer> set = new TreeSet<>();
for (Integer num : set) {
System.out.println(num);
}
这是个语法糖,编译成字节码后,编译器会替换成 iterator:解语法糖 (desugar)
- 首先调用 Set.iterator
- 然后调用 Iterator.hasNext
- 最后调用 Iterator.next
注意:数组类型的增强 for 循环不太一样,是使用 for-i 来实现的。
L1
LINENUMBER 9 L1
ALOAD 1
INVOKEINTERFACE java/util/Set.iterator ()Ljava/util/Iterator; (itf)
ASTORE 2
L2
FRAME APPEND [java/util/Set java/util/Iterator]
ALOAD 2
INVOKEINTERFACE java/util/Iterator.hasNext ()Z (itf)
IFEQ L3
ALOAD 2
INVOKEINTERFACE java/util/Iterator.next ()Ljava/lang/Object; (itf)
CHECKCAST java/lang/Integer
ASTORE 3
L4
LINENUMBER 10 L4
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 3
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
语法糖:
- 自动拆装箱也是一种语法糖,编译器会替换成 Integer.valueOf() 等
为什么需要迭代器:
对于不同的集合,都拥有各自的遍历模式。
那有没有一种方法,可以顺序的访问集合中的各个元素,而又不需要暴露该对象的内部表示。
设计模式:迭代器模式
public interface Iterator<E> {
// 返回true如果迭代对象还存在元素
boolean hasNext();
// 返回迭代对象中的下一个元素。如果不存在则抛出NoSuchElementException
E next();
// 删除此迭代器返回的最后一个元素(可选)。此方法在每次调用next时只能调用一次。
// 如果在迭代过程中,使用除了此方法以外的任何方式修改了底层集合,那么迭代器的行为是未指定的
default void remove() {
throw new UnsupportedOperationException("remove");
}
// 为每个剩余元素执行给定的操作,直到处理完所有元素或操作引发异常。
// 如果指定了迭代的顺序,则按照迭代的顺序执行操作。
// 操作引发的异常将被转发给调用者。
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
fail-fast 机制
如果在迭代器被创建之后,集合的结构被除了迭代器自己的 remove 和 add 方法以外的其他方式修改了,那么迭代器将会抛出 ConcurrentModificationException。因此,在面对并发修改时,迭代器会快速而干净地失败,而不是在将来某个不确定的时间冒任意的、不确定的行为的风险。
ArrayList的一段 JavaDoc:
The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
This class is a member of the Java Collections Framework.
注意:faild-fast 只能检测在迭代过程中是否有其他线程修改了集合,因为这类集合本身就不是线程安全的,所以不要依赖它来保证程序的正确性。