概述
关于使用迭代器对集合进行遍历时,不能对集合进行修改的论证## 标题 ##
摘要:迭代器再帮助我们进行对集合的元素进行遍历提供了有效的方法,java采用迭代器模式能在不暴露集合对象内部元素的情况下,对元素进行访问。
1.使用迭代器的优点
- Collection中的remove()方法需要先查找到需要删除元素的位置,这本身就需要一定的开销
- 如果在使用迭代器进行对集合的遍历时,对集合自身产生结构上的变化的时候(add.remove,clear等),例如:遍历时对集合当前向的下一项做了删除的操作,当再一次调用next(),就会出现混乱,下文会从源码的角度对其进行分析。
2.接口Iterator源码
public interface Iterator<E> {
//获取下一个元素,第一次调用给出第一项,第二次给出第二项,。。。
E next();
//是否存在下一个,存在true,不存在false
boolean hasNext();
//从底层集合中删除迭代器返回的最后一个元素,就是next()返回的集合中的元素
default void remove() {
throw new UnsupportedOperationException("remove");
}
//对每个剩余的元素进行一定的操作
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
3.测试实例
@Test
public void test_Iterator() {
List<String> list = new ArrayList<>();
list.add("唐三藏");
list.add("孙悟空");
list.add("猪八戒");
list.add("沙和尚");
list.add("白龙马");
for(Iterator<String> iter = list.iterator();iter.hasNext();{
if("猪八戒".equals(iter.next())) {
list.add("高小姐");
}
}
}
测试结果:java.util.ConcurrentModificationException
4.源码解读
private class Itr implements Iterator<E> {//Itr类作为ArrayList的内部类
int cursor; // 下一个元素的索引
int lastRet = -1; // 最后一个元素索引
int expectedModCount = modCount;//预期集合元素数量
public boolean hasNext() {
//size外部类集合的大小
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
//关键一步,调用checkForComodification()会去校验expectedModCount 和modCount是否相等,不等抛异常
//modCount 字段作为外部类结构修改次数的记录,为子类提供快速迭代,上文实例抛错就是出自此处
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];
}
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();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
源码解读:对集合进行迭代器遍历的时候,调用hashNext(),查看下一个元素的索引是否和集合的大小相等,相等表示已经到了集合的末尾,不存在下一个元素返回false;调用next()方法会先调用checkForComodification()方法来确保对集合修改次数一致,不一致抛异常,如果此时我们调用集合的remove(int index),就会去修改modCount 字段的次数,等下次再调用迭代器的next()方法的时候,值就会不一致 ,出现异常。同时,从逻辑的角度上来说,当我们对集合进行迭代的时候,如果对集合进行结构上的修改,直接会影响迭代器的遍历,产生不可预知的结果,所以在迭代器进行遍历的时候集合是不能对集合自身进行修改的。
最后
以上就是文静纸鹤为你收集整理的关于使用迭代器对集合进行遍历时,不能对集合进行修改的论证的全部内容,希望文章能够帮你解决关于使用迭代器对集合进行遍历时,不能对集合进行修改的论证所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复