foreach循环

​    foreach循环(Foreach loop)是计算机编程语言中的一种控制流程语句,通常用来循环遍历数组或集合中的元素。Java语言从JDK 1.5.0开始引入foreach循环。在遍历数组、集合方面,foreach为开发人员提供了极大的方便。通常也被称之为增强for循环。

​    在日常开发中,foreach循环用的非常多,但是有一点要非常小心,就是不能在这个循环里对数组或者集合里的元素进行remove或者add操作,否则会抛出java.util.ConcurrentModificationException

## 开发规范

​    在阿里巴巴java开发规范手册中有这样一种规定:

## 代码验证

package com.kobe.demo.collection;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; public class TestForList { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("111");
list.add("222"); for (String item : list) {
if ("222".equals(item)) {
list.remove(item);
}
} } }
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at com.kobe.demo.collection.TestForList.main(TestForList.java:15)

## 分析

​    因为foreach循环是Java提供的一种语法糖,所以我们用反编译工具将以上代码编译后看看:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
// package com.kobe.demo.collection; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; public class TestForList {
public TestForList() {
} public static void main(String[] args) {
List<String> list = new ArrayList();
list.add("111");
list.add("222");
Iterator var2 = list.iterator(); while(var2.hasNext()) {
String item = (String)var2.next();
if ("222".equals(item)) {
list.remove(item);
}
} }
}

​    显然,foreach循环实际上还是用Iterator迭代器while循环。根据堆栈信息,查看源码,可以看到是当调用ArrayList里的内部类Itr的checkForComodification()方法报错:

​    那我们看看modCount和expectModCount是什么?

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

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

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

​    再看到remove方法的核心操作:

​    可以看到,它只修改了modCount,并没有对expectedModCount做任何操作。

## 总结
   foreach循环里,遍历集合实际上是通过**迭代器Iterator**进行的,但是元素的remove/add方法却是使用的是**集合自己**的方法,导致在遍历的时候,会发现某个元素自己神不知鬼不觉地被删除/增加了,这时候,就会抛出一个异常,告诉用户可能会用多个线程对同一个集合发生了并发修改。

foreach循环里不能remove/add元素的原理的更多相关文章

  1. 为什么阿里巴巴Java开发手册中强制要求不要在foreach循环里进行元素的remove和add操作?

    在阅读<阿里巴巴Java开发手册>时,发现有一条关于在 foreach 循环里进行元素的 remove/add 操作的规约,具体内容如下: 错误演示 我们首先在 IDEA 中编写一个在 f ...

  2. 不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator 方式,如果并发操作,需要对 Iterator 对象加锁

    不要在 foreach 循环里进行元素的 remove/add 操作.remove 元素请使用 Iterator 方式,如果并发操作,需要对 Iterator 对象加锁. 正例: Iterator&l ...

  3. 为什么阿里巴巴禁止在 foreach 循环里进行元素的 remove/add 操作--java.util.ConcurrentModificationException

    摘要 foreach循环(Foreach loop)是计算机编程语言中的一种控制流程语句,通常用来循环遍历数组或集合中的元素. 在阿里巴巴Java开发手册中,有这样一条规定: 但是手册中并没有给出具体 ...

  4. 为什么禁止在 foreach 循环里进行元素的 remove/add 操作

    首先看下边一个例子,展示了正确的做法和错误的错发: 这是为什么呢,具体原因下面进行详细说明: 1.foreach循环(Foreach loop)是计算机编程语言中的一种控制流程语句,通常用来循环遍历数 ...

  5. 有关集合的foreach循环里的add/remove

    转自:Hollis(微信号:hollischuang) 在阿里巴巴Java开发手册中,有这样一条规定: 但是手册中并没有给出具体原因,本文就来深入分析一下该规定背后的思考. 1 .foreach循环 ...

  6. ArrayList之foreach循环删除倒数第二个元素,不触发fail-fast机制

    今天一朋友问了个问题,对于如下一段代码,运行后会有怎样的结果? public class ArrayListTest { public static void main(String[] args) ...

  7. JSTL中c:forEach循环里的值的substr操作及对String操作的常用API

    <c:forEach items="${dataList}" var="item" varStatus="itemStatus"> ...

  8. vector 循环里删除多个元素

    ; i < (int)vecLines.size(); i++) { AcDbLine * l1 = vecLines[i]; if (l1 == NULL) { continue; } //记 ...

  9. 腾讯一面!说说ArrayList的遍历foreach与iterator时remove的区别,我一脸懵逼

    本文基于JDK-8u261源码分析 1 简介 ​ ArrayList作为最基础的集合类,其底层是使用一个动态数组来实现的,这里"动态"的意思是可以动态扩容(虽然ArrayList可 ...

随机推荐

  1. python报错记录

    1.AttributeError: 'NoneType' object has no attribute 'group' import re s=r'<title>kobe<\tit ...

  2. 一文讲透静电放电(ESD)保护(转发)

    一直想给大家讲讲ESD的理论,很经典.但是由于理论性太强,任何理论都是一环套一环的,如果你不会画鸡蛋,注定了你就不会画大卫. 先来谈静电放电(ESD: Electrostatic Discharge) ...

  3. Cron表达式范例

    每隔5秒执行一次:*/5 * * * * ? 每隔1分钟执行一次:0 */1 * * * ? 每天23点执行一次:0 0 23 * * ? 每天凌晨1点执行一次:0 0 1 * * ? 每月1号凌晨1 ...

  4. react github项目

    https://github.com/bailicangdu/react-pxq 网址;https://github.com/bailicangdu/react-pxq

  5. 命令行下执行python找不包的解决方法

    首先我们来了解一下,为什么会出现这样的问题,以及python搜索包的机制是怎么样的 1.为什么会出现这样的问题? 包是向下搜索机制. 2.为什么ide中执行没有报找不到包的问题? python搜索机制 ...

  6. Pocket Gem OA: Log Parser

    time a given player spends actually connected to the network. We keep console logs of various game s ...

  7. flask下载文件---文件流

    html: <a name="downloadbtn" class="btn btn-success pull-right" href="/do ...

  8. 微信小程序案例大全

    微信小程序demo:足球,赛事分析 小程序简易导航 小程序demo:办公审批 小程序Demo:电魔方 小程序demo:借阅伴侣 微信小程序demo:投票 微信小程序demo:健康生活 小程序demo: ...

  9. centos7基于SVN+Apache+IF.svnadmin实现SVN的web管理

    一.介绍 本文介绍的是CentOS7上搭建基于Apache.SVN Server.iF.svnadmin实现web后台可视化管理SVN. iF.SVNAdmin应用程序是Subversion授权文件基 ...

  10. 解析搜狗实验室精简版数据:1、批量将.txt编码格式转化为utf8 2、解析提取数据

    在搜狗实验室里下载了精简版的数据,解压后是一个文件,里面有很多个.txt文档,里面编码格式都是ASCII.现需要将这些编码格式转化为utf-8,以下是python3语言编写的脚本,一般只需改变path ...