博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java普通for循环和增强for循环中做集合增删会不会出错?
阅读量:4256 次
发布时间:2019-05-26

本文共 3527 字,大约阅读时间需要 11 分钟。

       在遍及集合过程中对集合进行删除操作最好不要做,如果非要做可以利用迭代器,并发集合,或者同步代码。

       单线程模式下直接使用迭代器提供的remove方法就行或者首先记录下标遍历完后进行删除,多线程模式下建议使用同步或并发结合。

1 面试遇到的问题和迭代器没关系考察的是普通的for循环和foreach循环

下面先说出观点:

       普通for循环遍历集合过程中进行删除,如果进行大量删除会报IndexOutOfBoundsException异常,如果少量删除可以成功删除,但是循环的次数会减少,造成结果不准确。

      增强for循环遍历过程中进行删除,会报ConcurrentModificationException异常,这个异常大家应该很熟悉,并发修改异常。集合遍历时进行增删操作都需要留意是否会触发ConcurrentModificationException异常

下面写个简单的例子

public static void main(String[] args) {		ArrayList
datalist = new ArrayList
(); for(int i=0;i<100;i++) { datalist.add(i+"stringdata"); } int num = 0; Iterator
itea = datalist.iterator(); //删除不会出错 while(itea.hasNext()) { num++; if(num %2 ==0) { String str = itea.next(); itea.remove(); } } int count = 0; //少量删除不会报错,大量删除会报indexoutofbounds for(int i = 0;i
Exception in thread "main" java.util.ConcurrentModificationException	at java.util.ArrayList$Itr.checkForComodification(Unknown Source)	at java.util.ArrayList$Itr.next(Unknown Source)	at com.ldx.demo2.Test4.main(Test4.java:41)

2 为什么迭代器删除不会出错

集合都实现了自己的迭代器,从ArrayList进行迭代器的分析,ArrayList..iterator()获取迭代器,

迭代器不会出错原因:迭代器内部还是利用ArrayList的添加删除函数进行操作,只不过操作只有会对相应的指针进行修改(下一个),如果进行了删除操作,集合整体长度变小,指向下一个的指针也会相应减小,所以再次访问下一个时就不会发生错误了。

//获取迭代器 public Iterator
iterator() { return new Itr(); } private class Itr implements Iterator
{ int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; 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]; }//重点看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(); } } //modeCount 利用集合的操作可以修改,expectedModCount 则只有利用迭代器才能修改 //如果操作之前两个值不一样,就会报异常 final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }arrayList remove函数public E remove(int index) { rangeCheck(index); //修改modCount modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; }

 

看源码还可以发现ListIterator,是一个功能更加强大的Iterator,只能用于各种List类型的访问,ListIterator特点。

(1)可以向前,向后遍历.

(2)产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引.

(3)可以使用set()方法替换它访问过的最后一个元素.

(4)可以使用add()方法在next()方法返回的元素之前或previous()方法返回的元素之后插入一个元素.

转载地址:http://uspei.baihongyu.com/

你可能感兴趣的文章
java学习——发送激活邮件-就这么简单
查看>>
Android成长(一)——环境搭建
查看>>
SSH框架——走进Struts2
查看>>
Android成长(二)——两个页面交互
查看>>
Android成长(三)——页面布局
查看>>
bootstrap——完美的分页查询
查看>>
SSH——浅谈Spring中的IOC容器
查看>>
SSH——Struts2大战SpringMVC
查看>>
几番周折后的稳定
查看>>
Java时时调度(一)
查看>>
Java时时调度(二)
查看>>
SSH——Hibernate初学者之旅(一)
查看>>
SSH——浅谈spring中的事务(一)
查看>>
SSH——浅谈spring中的事务(二)
查看>>
java封装导出Excel
查看>>
SSH——Hibernate初学者之旅(二)
查看>>
SSH——Hibernate初学者之旅(三)
查看>>
SSH——Hibernate初学者之旅(四)
查看>>
SSH——Hibernate初学者之旅(五)
查看>>
SSH——Hibernate初学者之旅(六)
查看>>