删除ArrayList数组中某个元素,通常会使用for循环匹配目标元素完成删除操作。

public void remove(List<String> list, String str){Iterator<String> it = list.iterator();while(it.hasNext()){if(str.equals(it.next())){it.remove();}    }
}
public void remove(List<String> list, String str){for(String s: list){if(str.equals(it.next())){list.remove(s);}  }
}

  以上两种写法,第一种使用了显示声明迭代器Iterator的方式来遍历数组,匹配成功后删除;第二种使用JDK语法糖foreach的方式来遍历数组,匹配成功后删除。但是第二种写法会发生ConcurrentModificationException异常,简单来讲foreach是一个语法糖,其在进行遍历的时候还是使用的是ArrayList内部自己实现的迭代器Iterator,foreach的每次遍历都相当于调用Iterator的next()方法获取下一个元素,且方法内部会校验Iterator维护的expectedModCount是否等于ArrayList类维护的modCount,如不等就会抛出ConcurrentModificationException异常,又因为直接通过ArrayList的remove()方法来删除元素只会维护modCount,所以最终导致expectedModCount和modCount不相等。

ArrayList#remove

  抛开remove()方法中越界校验、移除后数组拷贝等逻辑,发现ArrayList在进行删除元素前会先将modCount属性自增加一来记录当前数组的修改次数。这就导致一边使用foreach语法糖遍历数组,一边使用ArrayList类remove()方法删除元素会发生ConcurrentModificationException异常。

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 workreturn oldValue;
}

Iterator

  ArrayList内部通过实现Iterator接口实现了一个迭代器,如下代码所示(省略部分代码):

  1. 每次调用迭代器的next()方法时,都会执行checkForComodification()方法的校验逻辑;
  2. checkForComodification()方法主要职责就是校验迭代器内属性expectedModCount和ArrayList类中属性modCount是否相等,不相等就抛出ConcurrentModificationException异常。

  迭代器中的remove()方法,首先会调用checkForComodification()方法来校验当前数组的修改次数是否相等;然后会调用ArrayList类中的remove()方法完成删除;最后再将执行删除操作后ArrayList类中modCount属性的最新值赋给expectedModCount以保持两值相等。

private class Itr implements Iterator<E> {int cursor;       // index of next element to returnint lastRet = -1; // index of last element returned; -1 if no suchint expectedModCount = modCount;@SuppressWarnings("unchecked")public E next() {checkForComodification();}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();}}final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}
}

ArrayList#removeIf

  想要删除数组中一个元素还可以使用ArrayList类的removeIf()方法,源代码逻辑可以参考下面六个步骤:

  1. 将modCount赋值给removeIf()方法局部变量expectedModCount;
  2. 使用for i 循环遍历数组每一个元素与目标删除元素比对,如果相等就将当前下标放入BitSet中标记为true(待删除元素);
  3. 校验局部变量expectedModCount与modCount是否相等,防止其它线程操作数组,如果两值不相等同样抛出ConcurrentModificationException异常;
  4. 再次for i循环遍历数组,利用BitSet完成删除目标元素、原地移动元素;
  5. 再校验一次局部变量expectedModCount与modCount是否相等,同样防止同时有其它线程在操作数组;
  6. 将modCount自增加一;

ArrayList删除元素的细则相关推荐

  1. java arraylist删除元素_java集合类ArrayList操作之删除remove某些元素的案例分析

    在java开发中,会经常出现需要删除java ArrayList的某些元素的场景,比如从在线用户列表的ArrayList中删除离线用户的ArrayList,但有的人会出现循环在线用户ArrayList ...

  2. [ArrayList删除元素] 你需要了解的ArrayList如何安全的删除重复元素/ list去重

    学习笔记使用 ArrayList特点:动态数组结构,元素有序,可重复的一个集合 import java.util.ArrayList; import java.util.Iterator; impor ...

  3. 如何在Java中处理ConcurrentModificationException? 在循环中从ArrayList中删除元素时要当心...

    从Java中从ArrayList中删除元素时常见的问题之一是ConcurrentModificationException. 如果您对索引使用经典的for循环或增强的for循环,并尝试使用remove ...

  4. Java 集合中遍历删除元素抛异常的原因,从ArrayList说起

    文章目录 使用for删除遗漏元素的原因: 使用foreach删除报错的原因: 其它集合的删除方法 删除集合元素的工具类 ArrayList删除元素的方式. 使用for循环删除.会遗漏删除的元素 使用f ...

  5. java arraylist 删除回车符_2种Java删除ArrayList中的重复元素的方法

    这篇文章将给出两种从ArrayList中删除重复元素的方法,分别是使用HashSet和LinkedHashSet. ArrayList是Java中最常用的集合类型之一.它允许灵活添加多个null元素, ...

  6. foreach迭代ArrayList时,真的不能删除元素吗?

    ArrayList是java开发时非常常用的类,常碰到需要对ArrayList循环删除元素的情况.这时候大家都不会使用foreach循环的方式来遍历List,因为它会抛java.util.Concur ...

  7. arraylist删除指定元素_面试官:谈谈常用的Arraylist和Linkedlist的区别

    Arraylist:底层是基于动态数组,根据下表随机访问数组元素的效率高,向数组尾部添加元素的效率高:但是,删除数组中的数据以及向数组中间添加数据效率低,因为需要移动数组. 例如最坏的情况是删除第一个 ...

  8. 大剑无锋之ArrayList中使用增强for循环能删除元素吗?【面试推荐】

    好久没写java代码,前几天面试被问到不少java的问题,其中一个接下来要说的. 先看几段代码. 第一段(集合中两个元素,判断条件是第一个元素) ArrayList<String> lis ...

  9. Arraylist理解(3)删除元素

    第三次强调,ArrayLIst是一个普通的类. 好,现在我们来讨论一下数组的删除,我们知道数组一但在堆内存中创建出来,数组长度是不可变的,看以下源码: 添加10个用户 比如我们要把"周八&q ...

最新文章

  1. NYOJ练习题 又见Alice and Bob
  2. 人行联网核查更新_又一批新职业公布,学互联网技术,等于站在就业“风口”...
  3. 2019.04.06 电商04 模板嵌套
  4. mysql申请审核系统_Mysql审核工具archery
  5. c++11标准:匿名函数(匿名表达式)lambda
  6. php 走马灯轮播,Vue.js轮播图走马灯代码实例(全)
  7. 推荐系统实践:从多领域优化到AutoML框架
  8. [转载] 朴素贝叶斯python实现预测_Python实现朴素贝叶斯分类器的方法详解
  9. 【机器人】机械臂与动捕Nokov的深入了解
  10. php 四级联动插件,JavaScript_jQuery实现的多选框多级联动插件,jQuery 实现的多选框联动插件 - phpStudy...
  11. Citrix Xendesktop虚拟化桌面和深信服VSP安全桌面的技术对比
  12. 系统越用越臃肿,你需要的系统瘦身技巧.
  13. matlab矩阵指定行求和,在matlab中对矩阵元素求和的有效(最快)方法
  14. 30天自制操作系统——自写设计
  15. shimano 型号详解 (zz)
  16. udal导mysql_teledb-udal实践分享
  17. dataframe更改columns
  18. chrome调试与设置 remote设备调试
  19. 7-1 sdut-Collection(Map)-1 读中国载人航天史,汇航天员数量,向航天员致敬
  20. lv双肩包尺寸对照表_lv双肩包mini尺寸对照表

热门文章

  1. 什么是云原生的应用?
  2. beforeSend 出现跨域问题,header里直接设置token就没问题----Day1
  3. 【CHATGPT-3.5】如何使用ChatGPT的同时并学习记忆
  4. 在C语言中使用二分法算法思想解决猜商品价格问题
  5. python开发简历自我介绍范文_你们简历上的自我介绍怎么写的?
  6. 市值一夜间蒸发千亿,拼多多离不开黄峥?
  7. JAVA编写学校超市选址问题_中小型超市商品管理系统设计与实现【开题报告+文献综述+毕业论文】.docx...
  8. echarts中国地图边缘设置阴影投影效果,并添加散点,大小根据数值改变
  9. python 处理Bus Hound 数据
  10. MOSS--SharePoint 开发学习一些总结