Java中的Iterator迭代器与fail-fast属性
什么是迭代器模式
迭代器模式(Iterator),提供一种方法访问集合内的元素并且不用了解该集合的内部细节。
这样使得对集合的遍历操作与具体的底层实现相隔离。
Iterator接口与fail-fast机制
在Iterator接口有四个方法:
boolean hasNext():如果还有元素可以进行迭代,返回true。
E next():返回迭代的下一个元素。
void remove():移除迭代器返回的最后一个元素。
void forEachRemaining():对集合中剩余的元素进行操作,直至元素完毕或抛出异常。
fail-fast机制是java集合中的一种错误机制。当多个线程对同一个集合内容进行操作时,就可能产生fail-fast事件。如:当多个线程对集合进行操作时,若其中一个线程通过Iterator遍历集合时,该集合内容被其他线程改变,就会抛出异常。
不止多线程,单线程也会出现fail-fast事件
ArrayList的Iterator实现
在ArrayList通过内部类Itr实现Iterator接口
在Itr类中有三个变量:
int cursor; //下一个元素的索引位置
int lastRet = -1; //上一个返回的元素的索引位置
//预期被修改次数,其中modCount表示列表结构被修改的次数,
//当列表内部结构发生改变时(add,set,remove)时,modCount+1
int expectedModCount = modCount;
看看具体的方法:
- hasNext()
public boolean hasNext() {
//判断下一个元素的索引是否等于集合的大小
return cursor != size;
}
- next()
public E next() {
//调用checkForComodification方法判断expectedModCount是否等于modCount
checkForComodification();
int i = cursor;
if (i >= size) //元素索引超出边界
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData; //ArrayList的底层数组
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
checkForComodification方法:
//判断expectedModCount是否等于modCount
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
- remove()
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();
}
}
ArrayList下触发fail-fast机制
多线程:
public class fail_fastTest {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Thread thread1 = new Thread() {
@Override
public void run() {
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
};
Thread thread2 = new Thread() {
@Override
public void run() {
try {
Thread.sleep(300);
list.add(4);// 修改集合
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
thread1.start();
thread2.start();
}
}
结果:
只输出两个数字就会报ConcurrentModificationException错误。
单线程:
public class fail_fastTest {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Iterator<Integer> iterator=list.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
list.add(4);
}
}
}
结果:
ListIterator
ListIterator继承于Iterator接口,只能用于各种List类型的访问。它比Iterator接口方法更多。
boolean hasNext(); //正向遍历,如果还有迭代元素返回true
E next(); //下一个迭代元素
boolean hasPrevious(); //逆向遍历,如果还有迭代元素返回true
E previous(); //前一个迭代元素
int previousIndex(); //返回对previous后续调用所返回元素的索引
void remove(); //移除由迭代器返回的最后一个元素
void set(E e); //用指定元素替换迭代器返回的最后一个元素
void add(E e); //将指定的元素插入集合