我是靠谱客的博主 愉快皮皮虾,最近开发中收集的这篇文章主要介绍ArrayList循环遍历并删除元素出现并发修改异常1. 第一种循环删除出现异常2. 第二种循环删除不报异常,但是会出现有些数据没有删除的情况3. 总结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

ArrayList循环遍历删除元素出现问题

  • 1. 第一种循环删除出现异常
  • 2. 第二种循环删除不报异常,但是会出现有些数据没有删除的情况
  • 3. 总结

1. 第一种循环删除出现异常

import java.util.ArrayList;
/**
* @author LanceQ
* @version 1.0
* @time 2021/4/28 19:16
*/
public class ListTest {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
for(String l:list){
System.out.println(list.remove(l));//并发修改异常
}
}
}

循环删除第二个开始爆并发异常

true
Exception in thread "main" java.util.ConcurrentModificationException
  • 先了解一下remove方法,其方法有两个,一个是下面这个通过对象删除,一个是通过索引删除。

public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
  • 一般情况下程序的执行路径会走到else路径下,最终调用faseRemove方法:

private void fastRemove(int index) {
modCount++;
//AbstractList中的变量
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
}
  • 其上面错误产生的原因:其实foreach写法是对实际的Iterable、hasNext、next方法的简写,问题在上文的fastRemove方法中,可以看到第一行把modCount变量的值加一,但在ArrayList返回的迭代器(该代码在其父类AbstractList中):

protected transient int modCount = 0;
public E next() {
checkForComodification();<--------这里
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
<----判断
throw new ConcurrentModificationException();<--------这里异常
}
int expectedModCount = modCount;

这里会做迭代器内部修改次数检查,因为上面的remove(Object)方法修改了modCount的值,所以才会报出并发修改异常。要避免这种情况的出现则在使用迭代器迭代时(显示或for-each的隐式)不要使用ArrayList的remove,改为用Iterator的remove即可。

import java.util.ArrayList;
import java.util.Iterator;
/**
* @author LanceQ
* @version 1.0
* @time 2021/4/28 19:16
*/
public class ListTest {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
//错误的删除方法
//
for(String l:list){
//
System.out.println(list.remove(l));//并发修改异常
//
}
System.out.println(list);
Iterator<String> it = list.iterator();
//这里判断的是下一个元素是否存在
while (it.hasNext()){
System.out.println(it.hasNext());
//需要进行next操作才可以进行remove,
// 否则会出现Java.lang.IllegalStateException异常(非法状态异常)
it.next();
it.remove();
}
System.out.println(list);
}
}
运行结果
[1, 2, 3]
true
true
true
[]
  • Java.lang.IllegalStateException异常(非法状态异常)出现的原因是 删除了一个不满足条件的元素。通过Iterator来删除,首先需要使用next方法迭代出集合中的元素,然后才能调用remove方法,否则集合可能抛出java.lang.IllegalStateException异常。

  • 注意remove对象是否存在,如果这个记录已被remove掉,再次remove会出现此异常,容易出现在对同一对象(如List)做多次迭代remove的情景中。

2. 第二种循环删除不报异常,但是会出现有些数据没有删除的情况

import java.util.ArrayList;
import java.util.Iterator;
/**
* @author LanceQ
* @version 1.0
* @time 2021/4/28 19:16
*/
public class ListTest {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
remove2(list);
}
private static void remove2(ArrayList<String> list) {
System.out.println(list);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.remove(i));
}
System.out.println(list);
}
}
运行结果
[1, 2, 3, 4, 5]
1
3
5
[2, 4]

这次的remove调用的是另一个remove方法


public E remove(int index) {
rangeCheck(index);
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;
}
  • 可以看到会执行System.arraycopy方法,导致删除元素时涉及到数组元素的移动。

  • 针对上方出现的运行结果与预想不一致,是由于在遍历第一个字符串时,因为符合删除条件,所以将该元素从数组中删除,并且将后一个元素移动(也就是第二个字符串b)至当前位置,导致下一次循环遍历时,后一个字符串并没有遍历到,所以无法删除。

针对这种情况可以倒序删除的方式来避免:


private static void remove2(ArrayList<String> list) {
System.out.println(list);
for (int i = list.size() - 1; i >= 0; i--) {
System.out.println(list.remove(i));
}
System.out.println(list);
}
[1, 2, 3, 4, 5]
5
4
3
2
1
[]

3. 总结

  • 通过foreach方式进行删除的modCount变量的改变,会出现非法状态异常,可通过iterator迭代器的方式进行判断,删除。

  • 通过for循环变量list的长度,正序来进行list中元素的移除,会出现漏删除的情况,可通过倒序删除的方式来解决。

参考:https://www.cnblogs.com/huangjinyong/p/9455163.html

最后

以上就是愉快皮皮虾为你收集整理的ArrayList循环遍历并删除元素出现并发修改异常1. 第一种循环删除出现异常2. 第二种循环删除不报异常,但是会出现有些数据没有删除的情况3. 总结的全部内容,希望文章能够帮你解决ArrayList循环遍历并删除元素出现并发修改异常1. 第一种循环删除出现异常2. 第二种循环删除不报异常,但是会出现有些数据没有删除的情况3. 总结所遇到的程序开发问题。

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

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

评论列表共有 0 条评论

立即
投稿
返回
顶部