1、说在前面的话
java的Iterator迭代器使用起来很简单,但是他是怎么实现的呢?有什么需要注意的点呢?我们准备看看源码来解答。
2、iterator的使用
使用Iterator很简单,大致代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class IteratorTest {
public static void main(String[] args) {
// 生成一个list
List<String> list = Stream.of("a", "b", "c", "d").collect(Collectors.toList());
// 获取到list的Iterator迭代器对象
Iterator<String> iterator = list.iterator();
// iterator.hasNext()用于判断是否还有元素待迭代
while (iterator.hasNext()) {
// 迭代出一个元素
String s = iterator.next();
// 我们可以移除这个元素
// iterator.remove();
// 打印出迭代出来的元素
System.out.printf(s);
}
}
}
3、源码分析
Iterator是list的一个内部类,先粘出Iterator的源码,后文再做针对性的解释:
1 | private class Itr implements Iterator<E> { |
其中,Iterator <E> 是一个迭代器接口,申明如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
通过上面的代码我们一般都可以看出个所以然来,大致逻辑不多说,里面有个细节重点说下:其中Iterator的每个方法都先调用了checkForComodification();【下面的代码片段】这个代码段用到了modCount和expectedModCount。modCount主要用来记录List被修改的次数,是list的成员变量;expectedModCount是Iterator的成员变量,用来记录Iterator所知道的list被修改的次数
这样做有什么好处呢?每当我们使用list的add、insert、remove等方法修改list时都会对modCount进行+1,而此时如果我们还在使用迭代器迭代数据,那么迭代器迭代的数据就会出问题,所以,我们要保证迭代器在迭代的过程中,list的数据没有被更改,也就是modCount==expectedModCount
1 | final void checkForComodification() { |
这也就是为什么在Iterator的remove()方法有 expectedModCount = modCount;
了,自己修改的数据当然可以正常遍历咯。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 移除当前cursor指向的元素
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);// 调用集合的删除方法
cursor = lastRet;// 注意,这里的cursor没有向下偏移
lastRet = -1;// 如果此元素被删除了,不能再被删了
expectedModCount = modCount;// 更新所知道的集合修改次数
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}