集合--迭代器
2018-08-09 本文已影响0人
sjandroid
目录
- Iterable
- Iterator
- ListIterator
- Spliterator
java主要容器类图(除Map外,因为Map并未实现Collection接口),从图中可以知道Collection接口实现了Iterable接口。
那Iterable是干嘛的呢??

Iterable
说明
该接口是从JDK1.5添加的,目的是 可以通过foreach语句遍历那么实现了该接口的类中的数据元素。
方法
iterator()
说明:返回一个迭代器实例。
使用
- 遍历集合类中的数据
private static void test_2(){
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
//while循环(显示调用Iterator)
//Iterator<String> iterator = list.iterator();
//while(iterator.hasNext()){
// System.out.println(iterator.next());
//}
//普通for循环(显示调用Iterator)
//for(Iterator<String> iterator2 = list.iterator(); iterator.hasNext();){
// System.out.println(iterator.next());
//}
//for-each遍历(隐式调用Iterator)
//for-each语法内部会调用Collection中的iterator()生成一个迭代器实例。
//其内部会调用iterator的hasNext()判断是否还有更多元素。调用next()方法,把返回的数据赋值为str。
for(String str : list){
System.out.println(str);
}
}
- 遍历自定义类中存储的数据元素
private static void test_1(){
Test<String> test = new Test<>(new String[]{"Who Are You?", "I am 雷锋."});
for(String str : test){
System.out.println(str);
}
}
/**
* 具体的Iterable实现类
*/
private static class Test<T> implements Iterable<T>{
private T[] array;
public Test(T[] array) {
this.array = array;
}
@Override
public Iterator<T> iterator() {
return new TestIterator<>(array);
}
/**
* 自定义迭代器
*/
private static class TestIterator<E> implements Iterator<E>{
private E[] array;
private int index;
public TestIterator(E[] array) {
this.array = array;
}
@Override
public boolean hasNext() {
return this.index < this.array.length;
}
@Override
public E next() {
return this.array[this.index++];
}
}
}
log
Who Are You?
I am 雷锋.
接下来看看Iterator是什么,以及它的作用是干嘛的吧。
Iterator
说明
方法:
hasNext():
说明:是否还有更多元素。
next():
说明:如果还有元素的话,则返回下一个元素。
remove():
说明:
1:从底层集合中移除此迭代器返回的最后一个元素。
2:调用此方法之前,需要调用next(),且next()方法调用后只可以调用该方法一次。(多次调用remove()会抛出IllegalStateException)
验证
在调用next()前调用remove()
private static void test_3(){
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
for(Iterator<String> iterator = list.iterator(); iterator.hasNext();){
iterator.remove();
System.out.println(iterator.next());
}
}
log
Exception in thread "main" java.lang.IllegalStateException
at java.util.LinkedList$ListItr.remove(LinkedList.java:923)
at com.iterator.Iterable_Foreach_Test_1.test_3(Iterable_Foreach_Test_1.java:63)
at com.iterator.Iterable_Foreach_Test_1.main(Iterable_Foreach_Test_1.java:20)
调用next()后,多次调用remove()
private static void test_3(){
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
for(Iterator<String> iterator = list.iterator(); iterator.hasNext();){
System.out.println(iterator.next());
iterator.remove();
iterator.remove();
}
}
log
1
Exception in thread "main" java.lang.IllegalStateException
at java.util.ArrayList$Itr.remove(ArrayList.java:872)
at com.iterator.Iterable_Foreach_Test_1.test_3(Iterable_Foreach_Test_1.java:65)
at com.iterator.Iterable_Foreach_Test_1.main(Iterable_Foreach_Test_1.java:20)
通过上述对Iterator的说明基本上在使用的时候做到了心中有数,接下来从源码入手,看一看Iterator的内部实现。
源码分析

接下来我们将从以下几点分析Collection中的迭代器实现。
- 什么是fail-fast
- AbstractList中的Iteraror实现
- ArrayList中的Iterator相较于AbstractList中的Iterator做了哪些优化
什么是fail-fast
fail-fast机制介绍:
- 说明:
fail-fast是一种 错误 机制,当检测到 容器 类的结构被进行了 不正确修改之后,则会抛出ConcurrentModificationException。 - 触发:
在使用迭代器时对 容器 类中的数据元素遍历,添加,删除,修改时。 - 作用:
用于提醒 容器 类的结构被进行了 不正确修改。 - 如何检测(检测依据):
迭代器中会保存容器类中modCount的一个副本,当利用迭代器进行遍历,添加,删除,修改操作时,会检测迭代器中的modCount与容器类中的modCount值是否一致,如果不一致则会抛出ConcurrentModificationException,此时fail-fast事件就产生了。
注意:
- modCount:该值是用于记录 AbstractList结构被修改的次数。那么什么操作会引起AbstractList的结构发生改变呢?
- 具体的例如List的add操作,remove操作等,这些方法都会对List的存储数据的列表大小发生更改。详细请查看 集合--ArrayList--基本方法使用说明 中关于subList()方法的介绍。
AbstractList中的Iteraror实现
private class Itr implements Iterator<E> {
/**
* Index of element to be returned by subsequent call to next.
* 记录要返回的下一个元素的索引。
*/
int cursor = 0;
/**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
* 1:调用previous()后,记录的是此元素之后的一个元素索引。
* 2:调用next()后,记录的是此元素之前的一个元素索引。
* 3:如果调用 remove()删除此元素,则该值重置为-1。
*
* 总结:
* 1:用于记录当前元素之前或者之后一个元素在列表中的位置。
* 2:调用next()/previous()后此值才会大于-1。调用remove()后此值被重置为-1。
*/
int lastRet = -1;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
* 1:用于同步AbstractList的modCount属性值。
* 2:如果检测到该值与AbstractList的modCount值不相等的话则会抛出
* ConcurrentModificationException。
*/
int expectedModCount = modCount;
//查看是否还有后续元素
public boolean hasNext() {
return cursor != size();
}
//返回列表中的下一个元素
public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
//从列表中移除调用next()后新近返回的元素
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount; //调用remove操作List的结构发生了更
改,此时需要同步modCount(remove会使modCount+1代表对列表结构进行了一次
修改)
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
//检查AbstractList是否发生了并发操作对AbstractList结构造成了错误的修改。
//比较Iterator的modCount是否与外部类中的modCount值一致
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
参考:
https://www.jb51.net/article/92127.htm
https://blog.csdn.net/u011518120/article/details/51932040
http://www.cnblogs.com/skywang12345/p/3308762.html