博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
为什么阿里巴巴禁止在 foreach 循环里进行元素的 remove/add 操作
阅读量:4180 次
发布时间:2019-05-26

本文共 3597 字,大约阅读时间需要 11 分钟。

一、代码编辑 

package com.xiaobu.test.List;import java.util.ArrayList;import java.util.Iterator;import java.util.List;/** * @author xiaobu * @version JDK1.8.0_171 * @date on  2019/3/4 17:32 * @description V1.0  fail-fast机制 */public class Demo4 {    private static List
userNames = new ArrayList
() { private static final long serialVersionUID = 3061248232613564555L; { add("Xiaobu"); add("Xiaobus"); add("xiaobu"); add("X"); } }; public static void main(String[] args) { removeIterator(); //removeIf(); //removeByFor(); //removeByForeach(); //removeByIterator(); } /** * @author xiaobu * @date 2019/3/7 10:23 * @descprition 结果 [xiaobu, X] * @version 1.0 推荐用这个 猜测最终实现是通过执行ArrayList的内部类 Itr的remove方法 * */ public static void removeIf() { userNames.removeIf(s -> s.contains("Xiaobu")); System.out.println(userNames); } /** * @author xiaobu * @date 2019/3/7 10:25 * @descprition 结果 [xiaobu, Xiaobus, X] * @version 1.0 因为list集合长度会缩短导致,导致元素前移 有可能造成数据的不准确性 */ public static void removeByFor() { int n = 0; for (int i = 0; i < userNames.size(); i++) { n++; System.out.println("u = " + userNames.get(i)); if (userNames.get(i).contains("Xiaobu")) { userNames.remove(i); } } System.out.println("n = " + n); System.out.println(userNames); } /** * @author xiaobu * @date 2019/3/7 11:46 * @descprition 直接调用的ArrayList的内部类 Itr的remove方法 * @version 1.0 */ public static void removeIterator() { Iterator iterator = userNames.iterator(); while (iterator.hasNext()) { String userName = (String) iterator.next(); if (userName.contains("Xiaobu")) { iterator.remove(); } } System.out.println(userNames); } /*** * @author xiaobu * @date 2019/3/7 10:28 * @descprition iterator remove方法 * @version 1.0 */ // TODO: 2019/3/7 Exception in thread "main" java.util.ConcurrentModificationException public static void removeByIterator() { Iterator iterator = userNames.iterator(); while (iterator.hasNext()) { String userName = (String) iterator.next(); if (userName.contains("Xiaobu")) { userNames.remove(userName); } } System.out.println(userNames); } /** * @author xiaobu * @date 2019/3/7 10:28 * @descprition foreach最终也是通过迭代器进行删除的 原理跟方法removeByIterator删除一致 * @version 1.0 */ // TODO: 2019/3/4 报错 Exception in thread "main" java.util.ConcurrentModificationException public static void removeByForeach() { for (String userName : userNames) { if (userName.contains("Xiaobu")) { //该方法调用的是ArrayList的remove方法 userNames.remove(userName); //只是删除一个 // break; } } System.out.println(userNames); }}

 

二、错误定位

 

 

modCount是ArrayList中的一个成员变量。它表示该集合实际被修改的次数。

expectedModCount 是 ArrayList中的一个内部类——Itr中的成员变量。expectedModCount表示这个迭代器期望该集合被修改的次数。其值是在ArrayList.iterator方法被调用的时候初始化的。只有通过迭代器对集合进行操作,该值才会改变。

Itr是一个Iterator的实现,使用ArrayList.iterator方法可以获取到的迭代器就是Itr类的实例。

 

removeByIterator和removeByForeach调用的是ArrayList的remove方法

 

 

这系列的remove操作只有modCount变化了expectedModCount没有发生改变导致两者不等,抛出ConcurrentModificationException 异常。

 


ArrayList的内部类 Itr的remove方法,有看到有修改到expectedModCount的值。modCount,expectedModCount两者是相等的。所以不会抛出异常。

转载地址:http://lfgai.baihongyu.com/

你可能感兴趣的文章
安装jdk的步骤
查看>>
简述JAVA运算符
查看>>
简易ATM源代码及运行结果
查看>>
简述Java中的简单循环
查看>>
用JAVA实现各种乘法表
查看>>
for双重循环实现图形
查看>>
Java类和对象基础
查看>>
简述Java继承和多态
查看>>
Java中Arrays工具类的用法
查看>>
简述JAVA抽象类和接口
查看>>
JAVA常用基础类
查看>>
简述Java异常处理
查看>>
简述Java集合框架
查看>>
jQuery+ajax实现省市区(县)下拉框三级联动
查看>>
Spring中的AOP 面向切面编程
查看>>
简述Spring中的JDBC框架
查看>>
MyBatis 动态SQL
查看>>
Spring MVC体系结构和处理请求控制器
查看>>
浏览器内核的整理稿
查看>>
暴力搜索内存空间获得API的线性地址
查看>>