java迭代器不能修改集合值_关于使用迭代器对集合进行遍历时,不能对集合进行修改的论证...

关于使用迭代器对集合进行遍历时,不能对集合进行修改的论证## 标题 ##

摘要:迭代器再帮助我们进行对集合的元素进行遍历提供了有效的方法,java采用迭代器模式能在不暴露集合对象内部元素的情况下,对元素进行访问。

1.使用迭代器的优点

Collection中的remove()方法需要先查找到需要删除元素的位置,这本身就需要一定的开销

如果在使用迭代器进行对集合的遍历时,对集合自身产生结构上的变化的时候(add.remove,clear等),例如:遍历时对集合当前向的下一项做了删除的操作,当再一次调用next(),就会出现混乱,下文会从源码的角度对其进行分析。

2.接口Iterator源码

public interface Iterator{

//获取下一个元素,第一次调用给出第一项,第二次给出第二项,。。。

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 list = new ArrayList<>();

list.add("唐三藏");

list.add("孙悟空");

list.add("猪八戒");

list.add("沙和尚");

list.add("白龙马");

for(Iterator iter = list.iterator();iter.hasNext();{

if("猪八戒".equals(iter.next())) {

list.add("高小姐");

}

}

}

测试结果:java.util.ConcurrentModificationException

4.源码解读

private class Itr implements Iterator{//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()方法的时候,值就会不一致 ,出现异常。同时,从逻辑的角度上来说,当我们对集合进行迭代的时候,如果对集合进行结构上的修改,直接会影响迭代器的遍历,产生不可预知的结果,所以在迭代器进行遍历的时候集合是不能对集合自身进行修改的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值