迭代器简介(Iterator)
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
import java.util.Iterator;
为什么要使用迭代器
迭代模式是访问(Collection)集合类的通用方法,只要集合类实现了Iterator接口,就可以用迭代的方式来访问集合类内部的数据,Iterator访问方式把对不同集合类的访问逻辑抽象出来,使得不用暴露集合内部的结构而达到循环遍历集合的效果。Iterator模式总是用同一种逻辑来遍历集合。
Map映射如何使用迭代器?
迭代器只针对集合类型的数据,但map集合提供了keySet()方法和value()方法,可以通过先将键值输出到一个集合,可以是list集合或者set集合,再使用迭代器去获取元素。
迭代器的优点
优点:
- 可以不了解集合内部的数据结构,就可以直接遍历;
- 不暴露内部的数据,可以直接外部遍历,提高安全性;
- 适用性强,基本上的集合都能使用迭代器;
Iterator和ListIterator区别:
- ListIterator有add()方法,可以向List中添加对象,而Iterator不能
- ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
- ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
- 都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。
Iterator的API
关于Iterator主要有三个方法:hasNext()、next()、remove()
- hasNext: 没有指针下移操作,只是判断是否存在下一个元素
- next:游标指针下移,返回 lastRet 所指向的元素
- remove:删除lastRet 指针所指向的元素,一般和next方法一起用,这时候的作用就是删除next方法返回的元素。并将游标前移,lastRet复位。 cursor = lastRet; lastRet = -1;
Iterator.remove()是唯一安全的方式来在迭代过程中修改集合。
如果在使用迭代器的过程中有其他的线程修改了List就会抛ConcurrentModificationException,这就是Fail-Fast机制。
foreach 本质上就是 Iterator。 实际上Iterator.remove内部也调用了ArrayList.remove 只不过后面又执行了 expectedModCount=modCount 防止移除元素后next取值变成第i+2个元素。
使用iterator.remove()方法前,一定先调用next()
使用迭代器iterator.remove()方法前,一定先调用next()方法来给变量lastRet进行赋值操作。否则lastRet = -1,会抛出 IllegalStateException()异常。
fail-fast策略–从线程安全的角度考虑
所谓fail-fast策略。这一策略在源码中的实现是通过 modCount 域,modCount 顾名思义就是ArrayList修改次数,对ArrayList 内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的 expectedModCount。在迭代过程中,判断 modCount 跟 expectedModCount 是否相等,如果不相等就表示已经有其他线程修改了 list:注意到 modCount 声明为 volatile,保证线程之间修改的可见性。
迭代器源码
public Iterator<E> iterator() {
return new Itr();
}
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
int cursor;//当前所指向元素的游标,初始iterator的游标为0
int lastRet = -1; //上个元素的索引,默认是-1
int expectedModCount = modCount;//modCount为ArrayList修改次数,
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];//给变量lastRet进行赋值操作。
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification(){
if(expectedModCount != modCount)
throw new ConcurrentModificationException();
}