2024年9月遍历arraylist时移除一个元素(Java中遍历ArrayList的过程中删除元素操作会发生并发修改异常)

 更新时间:2024-09-21 09:02:25

  ⑴遍历arraylist时移除一个元素(Java中遍历ArrayList的过程中删除元素操作会发生并发修改异常

  ⑵Java中遍历ArrayList的过程中删除元素操作会发生并发修改异常

  ⑶首先搞清楚不是x=n-不报错。是因为他避开了错误,实际当你用倒数第个来删除的时候,他就已经跳出循环,不会判断最后以为,这是为什么呢?

  ⑷我们先看看加强for循环是怎么实现的。都知道是通过迭代实现,那么将for写成迭代器来看。

  ⑸Iterator《Object》?itr?=?al.iterator();????????????while(itr.hasNext()){????????????????Object?o?=?itr.next();????????????????System.out.println(itr.hasNext());????????????????if(“n“?.equals(o)){????????????????al.remove(o);????????????}????????}

  ⑹以上就是加强for循环的真正样子。再来透析源代码。

  ⑺al.iterator():返回一个迭代器没什么好说的;

  ⑻itr.hasNext():通过判断?cursor(游标!=size(长度来决定是否结束循环,cursor(游标初始是每次经过?itr.next()+;当cursor==size时会跳出循环,这也是为什么倒数第个不会出错的主要原因;

  ⑼itr.next():看源代码可以发现每次在next()调用后,都会先调用checkForodification()这个方法;

  ⑽checkForodification():主要作用是判断itr迭代器数据是否和list一致,

  ⑾第一个?modCount集合结构变动次数,如:一开始你add调用了次,那么这个数就是,

  ⑿第二个?expectedModCount在调用iterator()方法时,初始化值等于modCount,

  ⒀这个方法判断当?modCount!=?expectedModCount时

  ⒁抛出异常ConcurrentModificationException,如果你调用迭代器的remove方法,expectedModCount会重新赋值,但是你调用的是list的remove方法,那么modCount就会+而expectedModCount不变,这就会造成?modCount!=?expectedModCount;

  ⒂最后,看看为什么倒数第个不会抛异常:

  ⒃当他遍历到“n-”时,cursor=,然后调用remover(o)方法,size=,这个时候调用了itr.hasNext()判断?cursor是否等于size,前面说过,当cursor==size时,跳出循环,那么就不会进入next(),也就不会进入checkForodification()方法,所以不会抛出异常,说白了,也就是循环次数少了一次。

  ⒄结合着源码看,应该会比较清晰。

  ⒅在for循环里遍历list,然后删除元素会怎样

  ⒆从list中删除指定元素可以使用remove方法来实现:ArrayListal=newArrayList();al.add(“a“);al.add(“b“);//al.add(“b“);//al.add(“c“);//al.add(“d“);for(inti=;i《al.size();i++){if(al.get(i)==“b“){al.remove(i);i--;}}在代码中,删除元素后,需要把下标减一。这是因为在每次删除元素后,ArrayList会将后面部分的元素依次往上挪一个位置(就是copy),所以,下一个需要访问的下标还是当前下标,所以必须得减一才能把所有元素都遍历完。

  ⒇详解遍历集合和遍历集合时删除集合元素

  ⒈集合遍历有多种方式,但各种方式执行效率上稍有差别,遍历集合时删除元素处理不当会有一些问题,这里详细汇总一下。

  ⒉遍历集合元素的方式主要有以下几种:

  ⒊这里以ArrayList为例来测试以上几种方式。先创建一个集合元素类。

  ⒋再创建一个遍历集合的测试类:

  ⒌在我的i-CPU电脑上多次测试取遍历操作耗时的平均值,得出这几种方法的遍历速度从快到慢依次为:

  ⒍所以如果遍历一个集合中元素,建议优先使用Java为Iterable接口提供的forEach默认方法。如果你还未使用Java,则建议优先使用Iterator接口的hasNex和next方法来实现遍历。

  ⒎遍历集合删除集合元素的方式有以下几种:

  ⒏这里以ArrayList为例来测试以上几种方式。

  ⒐在我的电脑上多次测试取耗时的平均值,得出这几种方法的遍历速度从快到慢依次为:

  ⒑其中,iteratorRemove和forRemoveNoSkipping的测试结果很接近,大家可以自行修改集合大小的常量亲自测试,如有问题欢迎反馈。

  ⒒所以如果遍历一个集合时删除其中的元素,建议优先使用Java提供的流式API来筛选集合元素。如果你还未使用Java,则建议优先使用逆序的一般for循环来实现遍历时删除集合元素。

  ⒓许多初学者容易使用上面示例中的前三种方式来在遍历集合时删除集合元素,但是得不到正确的结果,原因已经在这三种方法的注释中说明了。对于使用for-each循环时抛出ConcurrentModificationException异常的原因可通过查看ArrayList.remove()方法的源码来探明。for-each循环List集合时使用了一个实现了Iterator接口的ArrayList内部类对象来实现遍历,该内部类源码如下:

  ⒔使用for-each遍历时调用该内部类的next方法,进而调用该方法中第一行的checkForodification方法,ConcurrentModificationException异常就是在这个checkForodification方法中抛出的:

  ⒕当我们显式调用remove方法来删除集合中的元素时会修改modCount的值,使其与expectedModCount不一致:

  ⒖官方教程也有说在以下情况中可以使用Iterator来代替for-each循环:

  ⒗数组如何一边遍历一边删除元素

  ⒘这里一边遍历一边操作是不可取的,操作后集合也变了,之后遍历是改变后的集合。这里是另外一种方式实现。importjava.util.ArrayList;importjava.util.List;/****authorMFX*date年月日*/publilassas{publicstaticvoidmain(Stringargs){Lista=newArrayList();for(inti=;i《;i++){a.add(i);//集合添加元素}System.out.println(a);//打印Objectb=a.toArray();//转化为数组,目的为了的得到集合长度的另外一种表示System.out.println(b.length);//数组长度打印for(inti=;i《b.length;i++){//循环利用数组得到原来集合的长度a.remove();//集合操作删除这里只删除索引为,操作后集合是变了的,前面删除后后面补位上去}System.out.println(a);//打印System.out.println(a.size());//}}

  ⒙java中arraylist里面删除了一个元素,它的长度会自动减一吗其他元素的

  ⒚长度会自动减,在它后面的元素下标会自动减,前面元素下标不变,下面是测试:List《String》list=newArrayList《》();list.add(“a“);list.add(“b“);list.add(“c“);list.add(,“d“);System.out.println(list.size());//结果是list.remove();//删掉下标为的元素System.out.println(list.size());//长度减变成System.out.println(list.get());//获取下标为的元素,结果是c

  ⒛ArrayList使用forEach遍历时删除元素会报错吗

  ArrayList使用forEach遍历的时候删除元素会报错吗?其实不一定,如果删除的元素是倒数第二个则不会报错,否则报错ConcurrentModificationException。案例:List《String》lists=newArrayList《String》();lists.add(““);lists.add(““);lists.add(““);lists.add(““);如果要删除等于“”的元素,我们都知道ArrayList底层是类似数组的形式才存储数据的,生成一个元素后,后面的元素要往前移动,同时lists的size减。这时lists变成,大小为。使用forEach遍历时:for(Strings:lists){if(s.equals(““)){lists.remove(s);??}}//这是一颗语法糖,编译后相当于:for(Iteratori=lists.iterator();i.hasNext();){Strings=(String)i.next();if(s.equals(““)){list.remove(s);}}Iterator的hasNext()方法判断了size和当前下标cursor是否一样,一样则说明已经没有元素了。如果remove了“”这个元素之后,size会变成,这时候遍历的下标cursor刚好是,因此不会再进行下一次循环,直接结束了,此时元素“”是没有被遍历到的。假如lists中的元素是,即不再是倒数第二个元素了呢?此时会进行下一次循环,先判断i.hasNext(),发现当前下标cursor不等于size,执行i.next(),试图取出下一个值“”,这时候就报错了,原因在i.next()中:publicEnext(){??checkForodification();??inti=cursor;??if(i》=size)????thrownewNoSuchElementException();??ObjectelementData=ArrayList.this.elementData;??if(i》=elementData.length)????thrownewConcurrentModificationException();??cursor=i+;??return(E)elementData;}finalvoidcheckForodification(){??if(modCount!=expectedModCount)???thrownewConcurrentModificationException();}Iterator取下一个值时候会先判断modCount是否和expectedModCount一样,不一样就报错。????这里的modCount是删除的元素的数量计数,expectedModCount是Iterator期望的删除数量,使用Iterator的remove()方法的时候,Iterator会将调用ArrayList.this.remove(lastRet)删除元素同时使得modCount++,然后将modCount的值赋给expectedModCount,确保它们一样。所以到这里我们就可以发现问题了,在forEach循环体里,我们直接使用的是lists.remove(“”)的方法来删除元素,导致了expectedModCount和modCount不一致。所以要在遍历的时候删除元素,不能使用forEach遍历的方式,要使用Iterator的方法。Strings=null;for(Iteratori=lists.iterator();i.hasNext();){?s=(String)i.next();?if(s.equals(““)){???i.remove();?}}还有一种方法是使用CopyOnWriteArrayList代替ArrayList,这是一种写时复制的容器,每次添加删除元素的时候都会复制一份旧的数据,新建一个新数据,在新数据进行修改后再修改旧数据的指针指到新数据。这样的话,遍历的数据其实都是第一份的旧数据,旧数据是没有变的,我们使用旧数据遍历,使用新数据判断值。图:

  怎样从Arraylist中删除一个元素

  文件--》新建--》项目。

  选择为:控制台应用程序--》命名为:通过ArrayList集合插入和删除元素--》确定。

  导入命名空间和实例化对象。

  添加几个元素用于插入元素前的测试。

  向指定位置插入一个元素。

  如何删除ArrayList里面的所有元素

  arraylist删除一个元素,有两种方法.按下标删除如:list.remove(),list.remove(list.size()-);.按元素删除如:list.remove(list.get())删除第一个元素list.remove(list.get(list.size()-))删除最后一个元素

  任意删除ArrayList中的某一数据

  直接通过list的remove方法进行数据删除即可,因为list是有顺序的。按下标删除:list.remove();//删除下标为的list数据对象list.remove();//删除下标为的list数据对象备注:按对象删除,list.remove(obj)。删除元素的时候,下标都是从开始的。

您可能感兴趣的文章:

相关文章