Java ArrayList遍历foreach与iterator时remove的区别

目录
  • 一、Iterator和foreach的区别
    • 1.为啥说foreach底层就是Iterator
  • 二、foreach与iterator时remove的区别
    • 1.remove操作源码分析
    • 2.源码步骤
    • 3.为啥都是底层都是iterator,为啥foreach会报错
  • 三、查看源码方法

一、Iterator和foreach的区别

  • 多态差别(foreach底层就是Iterator)
  • Iterator是一个接口类型,他不关心集合或者数组的类型;
  • for和foreach都需要先知道集合的类型,甚至是集合内元素的类型;

1.为啥说foreach底层就是Iterator

编写的代码:

反编译代码:

二、foreach与iterator时remove的区别

先来看阿里java开发手册
但1的时候不会报错,2的时候就会报错(java.util.ConcurrentModificationException)

首先来看一下ArrayList中iterator方法的实现:

调用了new Itr(),生成Itr类(迭代器)。此时会给Itr的三个参数初始化。

  • cursor代表下一次的索引位置(开始是0)
  • size是集合的大小(2)

抛出异常类
next方法()的时候会检查checkForComodification是否相等

modCount修改计数(每次add和remove都会+1)expectedModCount期望的最大计数

1.remove操作源码分析

首先来看一下删除“2”的情况:
第一次循环:

因为此时的modCount和expectedModCount都为2(因为add了两次所以modCount为2),所以第一次循环中不会抛出异常,抛出异常都是发生在不是第一次循环的情况中。在next方法走完后,foreach循环方法体中的remove方法的if条件判断不满足,就结束了本次循环。
第二次循环:
第二次循环的hasNext和next方法都是能成功走完的,在这之后会进入到foreach循环方法体中的remove方法中,进行删除元素。而此时的size-1变为了1。在remove方法中的fastRemove方法中,会对modCount+1,也就变为了3。

第三次循环:

然后会走入到第三次循环中的hasNext方法中。按照正常的情况下该方法是会返回false的,但因为此时的size已经变为了1,而此时的cursor为2(cursor代表下一次的索引位置),所以两者不等,错误地返回了true,所以会继续走入到next方法中的checkForComodification方法中,判断此时的modCount和expectedModCount是否相等。因为此时的modCount已经变为了3,和expectedModCount的值为2不等,所以在此抛出了ConcurrentModificationException异常。
再来看一下删除“1”的时候为什么不会抛出异常:

第一次循环:

同上,此时的modCount和expectedModCount都为2,所以第一次循环中的hasNext和next方法都不会抛异常。在这之后会进入到foreach循环方法体中的remove方法中,进行删除元素。同上,size-1变为了1,而modCount+1变为了3。

第二次循环:

在第二次循环的hasNext方法中,此时的cursor为1,而size也是1,两者相等。所以hasNext方法返回false,就跳出了foreach循环,不会走到随后的next方法中,也就不会抛出异常。

2.源码步骤

第一次

第①句调用iterator(),

调用了new Itr(),生成Itr类(迭代器)。此时会给Itr的三个参数初始化。

此时expectedModCount == modCount == 2(因为list调动了add方法,add方法会对modCount实现++操作)
第②句调用下面hasNext()方法,返回下一个要访问元素的下标cursor,因为是第一次循环,所以cursor为0,size为2 (0 != 2 true)
第③句调用next()方法,foreach循环方法体中的remove方法的if条件判断不满足,就结束了本次循环

第二次

第②句调用下面hasNext()方法,返回下一个要访问元素的下标cursor,第二次循环,所以cursor为1,
size还是为2 (1 != 2 true)
第③句调用next()方法,正常取值,取到第一个元素"2";
第④句调用remove()方法,成功给list删除元素。注意,在调用remove方法的时候,有modCount++。所有此时,modCount3,expectedModCount2,size1

第三次

第②句调用下面hasNext()方法,返回下一个要访问元素的下标cursor,第二次循环,所以cursor为2,size为1
第③句调用next()方法,注意,在next()方法中第一句话就是调用checkForComodification();由于modCount(3) != expectedModCount(2),所以就抛了异常。

3.为啥都是底层都是iterator,为啥foreach会报错

当循环结束的时候,while (iterator.hasNext()) 会检查是否有下个元素存在,在remove删除2完成后,下次进入cursor还是1,size也是1.
foreach的话,删除remove2之后,下次进入cursor是2,size是1,所以返回false,要走next方法,然后,进行检查,modCount=3,而expectedModCount=2

三、查看源码方法

如果查看iterator下的ArrayList

remove也是如此

到此这篇关于Java ArrayList遍历foreach与iterator时remove的区别的文章就介绍到这了,更多相关Java ArrayList遍历内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java中ArrayList的使用详细介绍

    目录 1.ArrayList类 1.1ArrayList类概述 1.2ArrayList类常用方法 1.2.1构造方法 1.2.2成员方法 1.2.3示例代码 1.3ArrayList存储字符串并遍历 1.3.1案例需求 1.3.2代码实现 1.4ArrayList存储学生对象并遍历 1.4.1案例需求 1.4.2代码实现 1.5ArrayList存储学生对象并遍历升级版 1.5.1案例需求 1.5.2代码实现 总结 1.ArrayList类 1.1ArrayList类概述 在java中,我们会

  • Java8 ArrayList之forEach的使用

    目录 Java8 ArrayList之forEach使用 一.用法 二.效率 ArrayList在foreach中remove的问题分析 iterator itr.hasNext 和 itr.next 实现 倒数第二个元素的特殊 如何避坑 方法一,还是fori,位置前挪了减回去就行了, remove后i--: 方法二,不用ArrayList的remove方法,用Itr自己定义的remove方法,代码如下: Java8 ArrayList之forEach使用 之前使用Java8.顺便整理自己学到的

  • Java ArrayList与LinkedList及HashMap容器的用法区别

    目录 前言 一.ArrayList 1.原理 2.用法 二.LinkedList 1.原理 2.用法 三.HashMap 1.原理 2.用法 四.对比优缺点及区别 前言 Java中容器对象主要用来存储其他对象,根据实现原理不同,主要有3类常用的容器对象: 1.ArrayList 使用数组结构存储容器中的元素 2.LinkedList 使用链表结构存储容器中的元素 3.HashMap 使用Hash原理,同时使用数组和链表结构 一.ArrayList 1.原理 2.用法 打开Idea新建项目,右击s

  • Java中Arraylist的最大长度

    目录 Arraylist的最大长度 Arraylist的MAX_ARRAY_SIZE=Integer.MAX_VALUE-8; Arraylist的最大长度为2147483647即2^31-1 ArrayList的扩容问题 ArrayList的容量有两种 1.无参的构造方法 2.含参的构造方法 Arraylist的最大长度 Arraylist的MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 最近在学习java的基础知识,学到集合的时候,在查看ArrayList的源

  • Java中ArrayList在foreach里remove的问题详析

    前言 ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处: 动态的增加和减少元素 实现了ICollection和IList接口 灵活的设置数组的大小 都说ArrayList在用foreach循环的时候,不能add元素,也不能remove元素,可能会抛异常,那我们就来分析一下它具体的实现.我目前的环境是Java8. 有下面一段代码: public class TestForEachList extends BaseTests { @Test

  • Java中ArrayList同步的2种方法分享

    目录 方法一:使用Collections.synchronizedList()方法 方法2:使用CopyOnWriteArrayList 向量同步时为什么要使用arrayList? 前言: arrayList 的实现是默认不同步的.这意味着如果一个线程在结构上修改它并且多个线程同时访问它,它必须在外部同步.结构修改意味着从列表中添加或删除元素或显式调整后备数组的大小.改变现有元素的值不是结构修改. 有两种方法可以创建同步Arraylist: 1. Collections.synchronized

  • Java实现ArrayList排序的方法详解

    目录 简介 法1:JDK8的stream 法2:Comparator#compare() 法3:Comparable#compareTo() 简介 说明 本文用示例介绍Java的ArrayList排序的方法. List排序方法 主要有三种方法(按推荐度排序): JDK8的stream Comparator#compare() Comparable#compareTo() 法1:JDK8的stream 见:一文详解Java中Stream流的使用 法2:Comparator#compare() 需求

  • Java ArrayList遍历foreach与iterator时remove的区别

    目录 一.Iterator和foreach的区别 1.为啥说foreach底层就是Iterator 二.foreach与iterator时remove的区别 1.remove操作源码分析 2.源码步骤 3.为啥都是底层都是iterator,为啥foreach会报错 三.查看源码方法 一.Iterator和foreach的区别 多态差别(foreach底层就是Iterator) Iterator是一个接口类型,他不关心集合或者数组的类型; for和foreach都需要先知道集合的类型,甚至是集合内

  • java arrayList遍历的四种方法及Java中ArrayList类的用法

    java arrayList遍历的四种方法及Java中ArrayList类的用法 package com.test; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class ArrayListDemo { public static void main(String args[]){ List<String> list = new ArrayList<String

  • Java ArrayList遍历修改代码实例解析

    用for-each 边遍历ArrayList 边修改时: public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("aa"); list.add("bb"); list.add("cc"); list.add("dd"); System.out.println(list);

  • 面试题:java中为什么foreach中不允许对元素进行add和remove

    目录 1.foreach遍历ArrayList过程中使用 add 和 remove 2.追根溯源 2.1.modCount是什么? 2.2.expectedModCount 是什么? 2.3.熟悉的checkForComodification方法 2.4.流程回顾 3.避免fail-fast 机制 3.1.使用listIterator或iterator 3.2.使用CopyOnWriteArrayList 3.2.1.CopyOnWriteArrayList的add方法 3.2.2.CopyOn

  • JSP中c:foreach遍历和s:iterator遍历异同实例分析

    本文实例分析了JSP中c:foreach遍历和s:iterator遍历的异同.分享给大家供大家参考.具体如下: ①jstl c:foreach 首先我们来看一个普通的servlet: import com.xy.entity.Board; import com.xy.entity.Topic; import com.xy.entity.User; public class ToMainAction extends HttpServlet { private IBoarderDao boardDa

  • java ArrayList中的remove方法介绍

    先看一段代码,看看自定义的ArrayList中的remove设计是否有问题. public class MyArrayList { private Object[] mData = new Object[0]; private int mSize = 0; // 删除第i个元素 public void remove(int i) { if (i < 0 || i >= mSize) return; for (int index = i; index < mSize - 1; index+

  • java使用ArrayList遍历及效率比较实例分析

    本文实例讲述了java使用ArrayList遍历及效率比较.分享给大家供大家参考.具体如下: ArrayList arrL = new ArrayList(); ArrayList arrLTmp1 = new ArrayList(); ArrayList arrLTmp2 = new ArrayList(); ArrayList arrLTmp3 = new ArrayList(); ArrayList arrLTmp4 = new ArrayList(); for (int i=0;i<10

  • 详解JAVA中的for-each循环与迭代

    在学习java中的collection时注意到,collection层次的根接口Collection实现了Iterable<T>接口(位于java.lang包中),实现这个接口允许对象成为 "foreach" 语句的目标,而此接口中的唯一方法,实现的就是返回一个在一组 T 类型的元素上进行迭代的迭代器. 一.迭代器Iterator 接口:Iterator<T> public interface Iterator<E>{ boolean hasNext

  • 详解Java中的迭代迭代器Iterator与枚举器Enumeration

    迭代器Iterator接口 1.迭代器接口 Iterable 内置方法iterator(), 返回一个新建的 Iterator. 如: public interface Iterable { Iterator Iterator(); } Iterator 有 hasNext() 和 next() 两个方法要实现. public interface Iterator { boolean hasNext(); Item next(); void remove(); //可选实现 } 2.实现 导入

随机推荐