背景:业务中经常会涉及遍历list时对集合进行插入或者删除操作

一、 错误方式

先看看下面几段代码,1是foreach的方式去遍历list并删除元素,2是用迭代器的方式遍历list并删除元素,3是下标遍历

1. foreach

public  void  testDel(){List<Integer>  list  = Lists.newArrayList();for(int i=1;i<=5;i++){list.add(i);}for(Integer ele : list){if(ele == 3)list.remove(ele);}}

2. Iterator

public  void  testDel(){List<Integer>  list  = Lists.newArrayList();for(int i=1;i<=5;i++){list.add(i);}Iterator<Integer> iterator = list.iterator();while(iterator.hasNext()){Integer integer = iterator.next();if(integer==3)list.remove(integer);}}

以上两段代码的执行结果都是 java.util.ConcurrentModificationException。

在使用ArrayList时,当尝试用foreach或者Iterator遍历集合时进行删除或者插入元素的操作时,会抛出这样的异常:java.util.ConcurrentModificationException

关于这个异常的原因,看了很多文章,基本上解释如下:ArrayList的父类AbstarctList中有一个域modCount,每次对集合进行修改(增添、删除元素)时modCount都会+1。

而foreach的实现原理就是迭代器Iterator,在这里,迭代ArrayList的Iterator中有一个变量expectedModCount,该变量会初始化和modCount相等,但当对集合进行插入,删除操作,modCount会改变,就会造成expectedModCount!=modCount,此时就会抛出java.util.ConcurrentModificationException异常,是在checkForComodification方法中,代码如下:

final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();
}

那么,以上两种方式都不用呢,用下标遍历呢?看如下代码:

3 . 下标遍历

public void testDel() {List<Integer> list = Lists.newArrayList();list.add(1);list.add(2);list.add(2);list.add(2);list.add(2);for(int i=0;i<list.size();i++){if(list.get(i)==2){list.remove(i);}}}//结果: list = [1,2,2]

因为下标是固定死的自增,但list的大小在随着删除元素不停的减小,并且后面的元素往前移了1位,所以后面的元素遍历不到。在i=3时,由于删了2个元素,size=3,所以循环直接结束。因此这种方式也是不符合预期的。

二、解决方法

但业务中经常涉及遍历时删除或插入操作。所以如何安全的操作ArrayList呢,解决方法如下!

1.使用迭代器的remove方法

在使用迭代器遍历时,可使用迭代器的remove方法,因为Iterator的remove方法中 有如下的操作:

expectedModCount = modCount;

所以避免了ConcurrentModificationException的异常。代码如下:

public void testDel() {List<Integer> list = Lists.newArrayList();list.add(1);list.add(2);list.add(2);list.add(2);Iterator<Integer> iterator = list.iterator();while (iterator.hasNext()) {Integer integer = iterator.next();if (integer == 2)iterator.remove();}}执行后结果: list = [1]

其实在阿里巴巴Java开发手册中原话:不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。

2.倒序遍历删除

public void testDel() {List<Integer> list = Lists.newArrayList();list.add(1);list.add(2);list.add(2);list.add(2);list.add(2);for(int i=list.size()-1;i>=0;i--){if(list.get(i)==2){list.remove(i);}}}结果: list = [1]

可见,也达到了预期的效果。因为每次删除一个元素,list大小-1,但是倒序,循环条件为i>=0,所以list的size改变并没有对遍历造成影响,且元素的前移也不会对倒序遍历有影响。

所以在对list或者hashmap遍历时候进行元素删增操作时,一定要验证下,我开始想当然的以为OK,调试才发现前面几种方式是有问题的,不是异常,就是效果没达到预期。到线上会出大问题。所以整理了下,推荐最后两种方式!

List如何在遍历时删除元素相关推荐

  1. C++容器遍历时删除元素

    vector 错误做法 这样做会在遍历过程中越界导致程序崩溃 std::vector<int> vecInt({ 1, 3, 2, 1, 4, 1 });for (auto i = vec ...

  2. Map遍历时删除元素

    package ee;import java.util.HashMap; import java.util.Iterator;public class Demo {public static void ...

  3. Kotlin list在遍历时删除元素方法汇总

    方法一:Iterator迭代器 val list = arrayListOf("1", "2", "3", "4", & ...

  4. cocos2d-x CCArray用法 遍历和删除元素

    本文为 justbilt 原创,转载请标明原作者及原文出处,以示尊重! 作者:justbilt 原文:http://blog.justbilt.com/25/ 一.基本用法 1.声明初始化变量 C++ ...

  5. vector, list, map在遍历时删除符合条件的元素

    直接看源码,内有详细解释 /* 测试vector, list, map遍历时删除符合条件的元素 本代码测试环境: ubuntu12 + win7_x64 */ #include <iostrea ...

  6. Python - 遍历列表时删除元素的正确做法

    Python-遍历列表时删除元素的正确做法 一.问题描述 因为删除元素后,整个列表的元素会往前移动,而i却是在最初就已经确定了,是不断增大的,所以并不能得到想要的结果. 问题现象如下: a = [1, ...

  7. python 遍历list删除元素_详解Python遍历列表时删除元素的正确做法

    这篇文章主要介绍了详解Python遍历列表时删除元素的正确做法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 一.问题描述 这是 ...

  8. Python遍历列表时删除元素的几种方法

    问题来源: 删除列表中的指定元素 描述: 输入一个整数列表,并输入一个整数x,删除列表中所有值为x的数,再输出列表. 问题代码: a = list(eval(input())) x = eval(in ...

  9. go语言map遍历时删除是安全的, 且可以完全删除

    结论: map遍历时删除操作是完全的,且可以完全删除指定的元素 实验结果如下图: 代码如下: package main import ("fmt" ) func main() {x ...

最新文章

  1. 刚发版就被客户购买,升级后的神策用户画像究竟有什么魔力?
  2. cocos2d-x初探学习笔记(18)--Lable
  3. 数组的初始化与默认值
  4. VerifyRenderingInServerForm 和EnableEventValidation引发的两个问题
  5. linux重装lnmp,基于CentOS 6.5的LNMP安装过程
  6. WYSIWYG的意思。
  7. mysql 添加删除权限_MySQL实例讲解:添加账户、授予权限、删除用户
  8. python——os模块获取绝对路径
  9. 百分点集团刘译璟:人工智能四大挑战及对策
  10. python 中的意义_python3中 -的意义
  11. MongoDB安装、配置与示例
  12. 如何确定autosar的版本_什么是AUTOSAR?AUTOSAR的概要、背景以及目的-汽车电子-与非网...
  13. html网页设计课程心得,网页设计教学心得体会
  14. JAVA 如何控制模拟表单提交_java后端模拟表单提交
  15. 信息安全管理——网络安全监管
  16. 计算机二级方案管理器,计算机二级考试真题-Word-学生成绩管理系统需求分析
  17. 计算机网络概述上海电力,上海电力大学2021考研复试计算机网络考试大纲
  18. Coursera课程自然语言处理(NLP) 借助概率模型做自然语言处理 deeplearning.ai
  19. 四级英语高分必备完形填空2篇翻译
  20. js版的倒计时(月-日-时-分-秒-毫秒)

热门文章

  1. 更好地整理数据:windows下怎么让不同路径下的两个文件夹保持同步内容
  2. 北风网课程开放下载第一季
  3. 全局最优和局部最优 世俗理解以及原理解释
  4. Django基础(33): 中间件(middleware)的工作原理和应用场景举例
  5. Nginx服务器概述
  6. 链路聚合的原理以及配置
  7. 目的:python 解决输出乱码问题形如\u63a5\u53e3\u8c03\u7528\u6210\u529f
  8. 阿里云大数据之MaxComputer简介
  9. 南京移动开发者沙龙(创业邦+果合)
  10. 手写JavaScript