我是靠谱客的博主 丰富小蘑菇,最近开发中收集的这篇文章主要介绍那些年踩过JAVA迭代器的坑,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

我们知道 在遍历list的时候有三种方法

1 for 2each-for 3iterator

(增强for原理也是迭代器)

这些我们都是耳熟能详并且闭着眼睛都能写出来的,但我们在实际运用的时候并不是仅仅为了遍历,遍历一定是有目地的,我们遍历的目的,是为了确定某个值,或者实现对list的一些变化,比如增加删除或者改写。

在经过一番尝试后,我发现在我尝试判断集合里存在某个元素,或者某个元素达到某个标准的时候对集合实现改动的时候,总是会报错,常见的有2个异常

1 java.util.ConcurrentModificationException(并发修改异常)

2IndexOutOfBoundsException(索引超出边界异常)

首先我们谈索引超出边界异常,这个很简单,在很多情况下我们都有遇见,就连遍历一个数组列表什么的都会遇见,简而言之就是你要遍历index索引处的值,但这里没有值就会抛出这样一个异常!在遍历修改列表过程中我们是怎么遇到的呢?

举个例子,我们有一个size为4的arrlist,分别存0123四个值,现在我们要用for循环遍历列表,当遍历到2时删除

这时候for(int i=0;i<arr.size();i++){
if(arr.get(i)==3)

list.remove(i);

}信手拈来 (遍历+删除)但这就错啦!:因为list不像数组 在数组种你可以规定某个index的值为-1表示删除该元素 在遍历时候跳过,但是在arrlist中remove函数在使用后 还是以上一个arrlist为例 删除2的元素 那么arr的size会变成3,但是for循环会继续遍历,当到arr.size()-1时,这个列表的size早就减少了1,此时就索引越界了!

而正确的方法就是用迭代器给的方法删除————it.remove()

while(it.hasnext()){

int temp=it.next;

if(temp==2)

it.remove();}//这里可别用arr.remove(index)哈 用了就抛并发修改异常了!

而在add操作中就可以肆无忌惮的用for循环了!

因为你在一定条件下添加了东西,list会变长,因此他不会越界

但是在用迭代器遍历的同时进行添加操作 比如

while(it.hasnext()){

   int temp=it.next();

arr.add(temp);}       

这时候运行你会得到一个可爱的     ConcurrentModificationException !

其实包括上面为什么不能用arr.remove一样 他们的结果都是并发修改异常!那为什么会出现这种情况又如何避免呢,这就要从并发修改异常的源码说起了,为了简便(讲的话 懂得不用讲不懂得也看不懂)这里就不展示源码了,但为了严谨还是写了一些源码的内容

道理大概是 在arraylist的父类中有一个 AbstractList类,它是protected修饰的,也就是说子类(arrlist可以继承)它里面定义了一个modCount ,初始值为0,这个modCount 是表示list被修改的次数,每当我们add set remove时都会让这个modcount++

而iterator在用的时候会返回一个个Itr()的类的一个实例,它是ArrayList的一个成员内部类,会定义一个int expectedModCount = modCount;这个expectedModCount是表示预期修改的次数,然后我们用 it.next()的时候就会判断expectedModCount和modCount是不是相等的,如果是就继续,不是就会抛并发修改异常。(has.next()不判断  是next()判断)

为什么他要判断呢?不判断不是更方便吗?是因为iterator和list都是独自的参数,而迭代器的参数是依赖于list的,因此他需要得到list的相关参数来定自己的,所以在用iterator时要判断你的list修改过没有,而我们刚刚也说过(上面的下划线)一些操作会让list修改,这时候迭代器发现list动过当然会抛异常!

但是我们可以曲线救国,比如在添加时候不用迭代器而选择用for循环

在for循环中删除时候,为了防止越界,也可以把需要删除的index记录下来统一删除或者修改

但这真的很麻烦 所以肯定有更简便的方法!

iterator其实是由自己的remove方法的 所以上文我说不要用arrlist的remove方法,是因为iterator的remove方法是会让我们的预期修改值expectedModCount也随着++,(因为remove()会让modCount++),这时候他们还是相等的就不会抛并发修改异常!

那add,set呢?

其实是有一个子类listIterator继承自iterator的!这个子类提供了add,set,remove方法,我们可以用这个专属list的迭代器进行增删改 就不会发生并发修改异常了!

哦对了 list迭代器还有个好处就是可以倒着遍历!

这篇文章是为了理解原理才说了半天为什么要用llist迭代器的原因!

最后

以上就是丰富小蘑菇为你收集整理的那些年踩过JAVA迭代器的坑的全部内容,希望文章能够帮你解决那些年踩过JAVA迭代器的坑所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(73)

评论列表共有 0 条评论

立即
投稿
返回
顶部