看几段代码:
第一部分:
1 List list = new ArrayList(Arrays. asList(1, 2, 3, 5));2 for(Integer in : list) {3 if (in == 3) {4 list.remove(in);5 }6 }
第二部分:
1 List list2 = new ArrayList(Arrays. asList(1, 2, 3, 5, 6));2 for(Integer in : list2) {3 if (in == 3) {4 list2.remove(in);5 }6 }
第三部分:
1 List list3 = new ArrayList(Arrays. asList(1, 2, 3, 5, 6));2 for (Iterator iterator =list3.iterator(); iterator.hasNext();) {3 Integer integer =(Integer) iterator.next();4 if (integer == 3) {5 iterator.remove();6 }7 }
第四部分:
1 List list4 = new ArrayList(Arrays. asList(1, 2, 3, 5, 6));2 for (Iterator iterator =list4.iterator(); iterator.hasNext();) {3 Integer integer =(Integer) iterator.next();4 if (integer == 3) {5 list4.remove(integer);6 }7 }
第一部分没有报错,但是有潜在问题,
第二部分:java.util.ConcurrentModificationException
第三部分:没有问题,正确删除方式。
第四部分:java.util.ConcurrentModificationException
如果从一个ArrayList获得了一个iterator后,通过这个iterator的add和remove方法之外的途径修改了ArrayList的内容,那么这个iterator就会迅速失效。一个ArrayList内部的iterator中,next/previous/add/set/remove等会改变ArrayList或iterator状态的方法都会调用checkForComodification方法来检查是否发生了预期之外的修改。如果有这样的修改,则抛出异常使该iterator不再起作用。
第一部分删除时,该list的size减少了1,正好等于for-each循环所使用的iterator的cursor的值。于是在删除之后,回到hasNext()的检查就通不过了,退出循环。这个情况下list的最后一个元素并没有被遍历;其it.next()方法没有被调用,因而没有出现ConcurrentModificationException。
第二部分删除时。list的size仍然大于iterator中cursor的值,那么循环会继续,在调用到it.next()的时候就抛出异常了。
第四部分删除时,调用了原list4的remove(object),而不是iterator的remover()方法 ,混合使用后,出现的情况和第二部分一致,所以报了同样的错误。
一般在开发过程中,遍历删除往往从后往前遍历:
1 for(int j=list.size()-1;j>=0;j--){2 list.remove(j);3}
另外,也可以从前往后遍历:
1 for (int i = 0; i < list.size(); i++) {2 list.remove(i);3 i--;4 }
往往在全部删除时直接使用api,list.removeAll();
遍历效率:
RandomAccess接口是List 实现所使用的标记接口,用来表明其支持快速(通常是固定时间)随机访问。此接口的主要目的是允许一般的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能。
在对List特别的遍历算法中,要尽量来判断是属于RandomAccess(如ArrayList)还是SequenceAccess(如LinkedList),因为适合RandomAccess List的遍历算法,用在SequenceAccess List上就差别很大,即对于实现了RandomAccess接口的类实例而言,此循环
for (int i=0, i
list.get(i);
的运行速度要快于以下循环:
for (Iterator i=list.iterator(); i.hasNext(); )
i.next();
下标遍历要比增强for循环的效率高