-
2021-01-26 13:41:26
JAVA中循环遍历list有三种方式for循环、增强for循环(也就是常说的foreach循环)、iterator遍历。
1、for循环遍历listfor(int i=0;i<list.size();i++){ if(list.get(i).equals("del")) list.remove(i); }
这种方式的问题在于,删除某个元素后,list的大小发生了变化,而你的索引也在变化,所以会导致你在遍历的时候漏掉某些元素。比如当你删除第1个元素后,继续根据索引访问第2个元素时,因为删除的关系后面的元素都往前移动了一位,所以实际访问的是第3个元素。因此,这种方式可以用在删除特定的一个元素时使用,但不适合循环删除多个元素时使用。
2、增强for循环
for(String x:list){ if(x.equals("del")) list.remove(x); }
这种方式的问题在于,删除元素后继续循环会报错误信息ConcurrentModificationException,因为元素在使用的时候发生了并发的修改,导致异常抛出。但是删除完毕马上使用break跳出,则不会触发报错。
3、iterator遍历
Iterator<String> it = list.iterator(); while(it.hasNext()){ String x = it.next(); if(x.equals("del")){ it.remove(); } }
这种方式可以正常的循环及删除。但要注意的是,使用iterator的remove方法,如果用list的remove方法同样会报上面提到的ConcurrentModificationException错误。
总结:
(1)循环删除list中特定一个元素的,可以使用三种方式中的任意一种,但在使用中要注意上面分析的各个问题。
(2)循环删除list中多个元素的,应该使用迭代器iterator方式。更多相关内容 -
详解Java中list,set,map的遍历与增强for循环
2020-08-31 11:17:43主要介绍了详解Java中list,set,map的遍历与增强for循环的相关资料,需要的朋友可以参考下 -
增强For循环以及集合遍历语法糖
2022-03-06 12:18:48增强For循环以及集合遍历语法糖-
什么是增强For
增强for循环是for的一种新用法!用来循环遍历数组和集合。优缺点:只能从头到尾的遍历数组或集合,而不能只遍历部分;在遍历List或数组时,不能获取当前元素下标;增强for使用便简单,这是它唯一的优点了; 增强for比使用迭代器方便一点!其实增强for内部是使用迭代器完成的!也就是说,任何实现了Iterable接口的对象都可以被增强for循环遍历!这也是为什么增强for可以循环遍历集合的原因(Collection是Iterable的子接口)。
注意:Map并没有实现Iterable接口,所以你不能直接使用增强for来遍历它!-
增强For测试代码:
//没有学集合的只需要看1-13行代码 //传统的数组遍历 String[] persons = {"张三", "李四", "王五"}; for (int i = 0; i < persons.length; i++) { System.out.println(persons[i]); } //使用增强for循环的数组遍历 //这里的String person等价于上面for的int i =0; //persons就是你遍历的变量名 //由于不能取游标所以没有上面的persons[i]那种 for (String person : persons) { System.out.println(person); } //传统的Iterator遍历集合 List<String> Listpersons =new ArrayList<String>(); Listpersons.add("张三"); Listpersons.add("李四"); Listpersons.add("王五"); for(Iterator<String> i=Listpersons.iterator();i.hasNext();){ String person=i.next(); System.out.println(person); } //使用增强For循环遍历集合 for(String person: Listpersons){ System.out.println(person); }
-
集合遍历语法糖测试代码
//Persons集合 List<String> Listpersons =new ArrayList<String>(); Listpersons.add("张三"); Listpersons.add("李四"); Listpersons.add("王五"); //使用语法糖遍历集合 Listpersons.forEach(System.out::println);
-
-
Java中使用增强for循环遍历List, remove或add元素出现异常的总结
2019-08-28 22:50:02foreach循环是计算机编程语言中的一种流程控制语句, 一般用来循环遍历数组跟集合, 获取里面的元素; Java从JDK 1.5开始引入foreach循环, 在遍历集合跟数组, 十分的方便, 也叫作增强for; foreach的语法格式如下图所示...foreach循环是计算机编程语言中的一种流程控制语句, 一般用来循环遍历数组跟集合, 获取里面的元素; Java从JDK 1.5开始引入foreach循环, 在遍历集合跟数组, 十分的方便, 也叫作增强for;
foreach的语法格式如下图所示
其遍历List的代码如下图所示:
输出的结果为
可以从代码看跟输出结果看出来, 使用foreach遍历集合或者数组的时候, 可以起到普通for循环同样的效果, 并且代码格式上更加整洁; 但是作为程序开发人员来说, 只是知道增强for的使用还是不够的, 防止知其然而不知其所以然这样的尴尬局面; 除了熟练应用以外, 更加重要的是要熟悉其原理; 增强for循环是Java提供的一个语法糖(语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会), 将以上代码的class文件反编译后可以看到源码:
很明显, 所谓的增强for其实是依赖了while循环和Iterator实现的, 那么重点来了, 尝试在foreach循环中对list的元素进行add和moved操作的时候会发生什么?
首先使用双括弧语法(duble-brace syntax)建立并初始化一个List, 其中包含四个字符串, 分别是Hollis, hollis, HollisChuang, H
然后使用普通for循环对List进行遍历, 删除List中元素为Hollis的元素, 然后输出List, 结果如下:
这是使用普通for循环对List中的元素进行操作, 结果输出很正常, 那么再验证一下使用增强for进行操作会是什么结果?
使用增强for遍历操作List, 会抛出以下异常:
之所以会抛出这个异常的原因是因为该操作方法触发了一个Java集合的错误检测机制: fail-fast;
fail-fast, 即快速失败, 它是Java集合的一种错误检测机制; 当多个线程对集合(非fail-safe的集合类)进行结构上的操作的时候, 就有可能产生fail-fast机制, 这个时候就会抛出ConcurrentModificationException(当方法检测到对象的并发修改, 但不允许这种修改时就抛出该异常); 即使在非多线程环境, 单线程操作中违反了规则, 同样也会有可能抛出该异常;
运行以上代码,同样会抛出异常。看一下ConcurrentModificationException的完整堆栈:
通过异常堆栈可以看到,异常发生的调用链ForEachDemo的第23行,Iterator.next
I
调用了Iterator.checkForComodification
方法 ,而异常就是checkForComodification方法中抛出的。其实,经过debug后,可以发现,如果remove代码没有被执行过,iterator.next这一行是一直没报错的。抛异常的时机也正是remove执行之后的的那一次next方法的调用。checkForComodification方法的代码,看下抛出异常的原因:
代码很明显, 当modCount != expectedModCount的时候, 就会抛出异常
通过翻源码,可以发现:modCount是ArrayList中的一个成员变量。它表示该集合实际被修改的次数。expectedModCount 是 ArrayList中的一个内部类——Itr中的成员变量。expectedModCount表示这个迭代器期望该集合被修改的次数。其值是在ArrayList.iterator方法被调用的时候初始化的。只有通过迭代器对集合进行操作,该值才会改变。Itr是一个Iterator的实现,使用ArrayList.iterator方法可以获取到的迭代器就是Itr类的实例。
之间的关系如下
再往下看, remove方法的核心逻辑如下
它只修改了modCount,并没有对expectedModCount做任何操作。之所以会抛出ConcurrentModificationException异常,是因为代码中使用了增强for循环,而在增强for循环中,集合遍历是通过iterator进行的,但是元素的add/remove却是直接使用的集合类自己的方法。这就导致iterator在遍历的时候,会发现有一个元素在自己不知不觉的情况下就被删除/添加了,就会抛出一个异常,用来提示用户,可能发生了并发修改。
那么开发过程中遇到此类场景, 应该如何去正确的使用循环?
1,
直接使用普通for循环进行操作
不能在foreach中进行,但是使用普通的for循环还是可以的,因为普通for循环并没有用到Iterator的遍历,所以压根就没有进行fail-fast的检验。
2,
直接使用Iterator进行操作
除了直接使用普通for循环以外,我们还可以直接使用Iterator提供的remove方法。
如果直接使用Iterator提供的remove方法,那么就可以修改到expectedModCount的值。那么就不会再抛出异常了。其实现代码如下:
3,
直接使用fail-safe的集合类
在Java中,除了一些普通的集合类以外,还有一些采用了fail-safe机制的集合类。这样的集合容器在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发ConcurrentModificationException。
基于拷贝内容的优点是避免了ConcurrentModificationException,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。
4,
使用增强for循环其实也可以
如果,我们非常确定在一个集合中,某个即将删除的元素只包含一个的话, 比如对Set进行操作,那么其实也是可以使用增强for循环的,只要在删除之后,立刻结束循环体,不要再继续进行遍历就可以了,也就是说不让代码执行到下一次的next方法。
-
List用增强for循环遍历出现的小问题
2019-12-12 11:22:05用增强for循环遍历List中的元素时,如果循环体中做了删除操作报出如下异常: Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification...问题描述
用增强for循环遍历List中的元素时,如果循环体中做了删除操作报出如下异常:
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 test.main(test.java:13)
复现问题
public class test { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); for (int i = 0; i < 5; i++){ list.add(i); } for (Integer i : list){ if (i == 4){ list.remove(i); System.out.println("remove"); } } } }
看看问题是怎么产生的
=.=反编译我是不会啦,贴个别人的
https://blog.csdn.net/puppet121/article/details/81546260
也就是增强for循环到了虚拟机会变成Iterator执行for(java.util.Iterator i$ = list.iterator(); i$.hasNext();) { String s = (String) i$.next(); { list.remove(s); } }
先了解modCount:记录对“影响了List size”的操作 次数
- modCount
The number of times this list has been structurally modified.
Structural modifications are those that change the size of the list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.
然后看抛异常的地方:
private class Itr implements Iterator<E> { /** * 这是ArrayList的内部类,Itr在我们执行遍历操作的时候被初始化,expectedModCount = 我们执行的5次插入操作 */ int expectedModCount = modCount; public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } }
然而执行list.remove(Object obj)后,调用的是ArrayList自己的remove方法,虽然modCount+1,但是用于遍历List的itr对象中的expectedModCount依然=5,这样就在遍历下一个元素是就被检查出不一致抛异常啦~
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
正确的处理姿势
List<Integer> list = new ArrayList<>(); for (int i = 0; i < 5; i++){ list.add(i); } Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()){ int i = iterator.next(); if (i == 1){ //要领就是:既然外面用的iterator遍历,那里面也要用iterator删除,这样就保证两个操作数的一致性啦 iterator.remove(); } }
--------我是分界线------------
mentor看代码刚问完会不会有问题 瞬间就抛了异常。。。 - modCount
-
JAVA中循环遍历list有三种方式for循环、增强for循环(也就是常说的foreach循环)、iterator遍历。
2018-07-06 09:45:341、for循环遍历list for(int i=0;i<list.size();i++){ if(list.get(i).equals("del")) list.remove(i);}这种方式的问题在于,删除某个元素后,list的大小发生了变化,而你的索引也在变化,... -
Java普通循环遍历 与 增强for循环遍历
2022-03-18 12:01:10import java.util.List; public class Add_FOR { public static void main(String[] args) { String[] arr={"hello","你好","你好不好","你很好"}; for (int i=0;i<arr.length;i++){ System.out.println(arr... -
for循环遍历list集合组拼成字符串StringBuilder,及处理最后一个逗号
2021-03-16 21:06:55方法一:拼接过程中自动处理逗号publicstaticvoidmain(String[]args){StringBuilder str=new StringBuilder();List list=new ArrayList();...i{if(i==list.size()-1)//当循环到最后一个的时候 就... -
List集合循环遍历
2022-01-13 10:10:571.增强for循环遍历 2.一般for循环遍历 3.迭代器循环遍历 package com.jpa.demo; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Testssss { public static void... -
for循环遍历
2021-06-07 08:57:281、遍历循环 for (循环变量类型 循环变量名称;循环条件;更新语句) 循环体 String[] arr = { “a”, “b”, “c”, “d” }; for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } 打印台 a b... -
三种for循环遍历
2021-03-07 23:28:32import java.util.ArrayList;import java.util.Iterator;...public class For{public static void main(String[]args) {//new一个集合对象List alList=new ArrayList();alList.add(1);//自动转成Integeral... -
java之遍历增强for循环—Foreach方法
2022-01-25 17:35:32增强four循环:底层使用的是迭代器,使用for循环的格式。简化了迭代器的书写,是jdk1.5之后出现的新版本 Collection<... 增强for循环:用来遍历集合和数组; 格式: for(集合/数组的数据类型 变量名 ... -
浅谈普通for循环遍历LinkedList弊端
2021-02-05 09:47:00java开发过程中,用到的最多...对于ArrayList的遍历,通常是下面的方法: public static void main(String[] args){List arrayList =new ArrayList();for (int i = 0; i < 100; i++)arrayList.add(i);for (int i... -
Java: 增强for循环针对list的时候,是严格按照list的顺序依次遍历的吗?
2021-03-05 23:34:11是的首先写一个测试代码:`private void for_Test(){List list =new ArrayList<>();list.add(1);list.add(2);list.add(3);for(int i :list){System.out.println(i);}}`编译成字节码:由于主要是看迭代顺序所以... -
增强for循环遍历 数组,Collection,Map
2018-08-14 09:47:42增强for循环:数组,Collection,Map public class Demo { public static void main(String[] args) { /* * 增强for循环:数组,Collection,Map * for(元素类型 变量:数组/Collection){ * 循环体 ... -
集合--List集合,增强for循环
2020-12-15 09:26:24什么是集合? 简称集,是用来存储多个元素的容器 集合和数组的区别 元素类型 集合:引用类型(存储基本类型时自动装箱) 数组:基本类型、引用类型 元素个数 集合:不固定,可任意扩容 ...一、List集合 -
JAVA中循环遍历list有三种方式
2021-02-12 10:19:45转自:https://blog.csdn.net/changjizhi1212/article/details/81036509JAVA中循环遍历list有三种方式for循环、增强...1、for循环遍历listfor(int i=;iif(list.get(i).equals("del"))list.remove(i);}这种方式的问... -
Java Collection List三种遍历方式,增强for循环,索引for循环,迭代器;
2022-03-07 22:40:40import java.util.*; public class ListDemo1 { ... List<Student> list = new ArrayList<Student>(); Student stu1 = new Student("林黛玉", 18); Student stu2 = new Student("西施舌", 18); . -
【Java】四种方法遍历List集合元素(Iterator、ListIterator、普通for、增强for)
2022-01-29 19:44:33首先是List集合test2的创建和元素的写入: List<String> test2 = new ArrayList<>(); test2.add("1"); test2.add("2"); test2.add("3"); 注意,要用多态的方式创建List集合。 方法一.Iteator... -
java增强型for循环 三种遍历集合方式
2018-11-10 07:30:09java增强型for循环 三种遍历集合方式 -
Java中数组和集合的for循环遍历
2022-04-04 05:23:45传统的for循环遍历方式是 //对于数组而言 int[] arr=new int[10]; for(int i=0;i list=new ArrayList(); for(Iterator i=list.iterator();i.hasNext();){ person=i.next(); System.out.println(person); } 现在有了... -
增强版for循环以及list
2021-02-17 21:03:20addAll()方法参数为一个集合对象,可以将集合对象里的所有元素添加进来 可以通过for循环遍历集合 remove方法删除元素,参数既可以是索引也可以是数据 get方法得到的集合元素是object类型的,不能直接进行运算,需要... -
增强的for循环遍历期间删除集合元素的问题
2019-04-24 21:04:04现在我想删除前五个,要求用一次for循环,问问该怎么做到? 我当时想这道题肯定没有那么简单,应该不是常规思路可以解决的。于是,我给出的我的解决思路是,开辟一个集合把后五个元素加入其中,然后覆盖掉原来... -
Java之增强的for循环遍历数组、集合及Map
2018-10-13 22:06:01视频地址: Java之增强的for循环遍历数组、集合及Map 更多精彩内容,敬请扫码关注(HelloWorld小码农): -
Android Kotlin for循环 when List集合 的用法
2022-04-23 22:33:26Kotlin for循环 when List集合 的用法 1.for循环的四种用法 for(i in 2 .. 5){ } for(i in 5 downTo 2){ } for (i in 1 until 10){ } for(i in 2 .. 5 step 2){ } 2.List 集合 实例化集合 遍历集合 var... -
如何有效的使用 for循环和Iterator遍历
2019-11-05 17:36:54使用for循环遍历的速度会比Iterator遍历的速度要快: for (int i=0, n=list.size(); i < n; i++) list.get(i); runs faster than this loop: for (Iterator i=list.iterator(); i.hasNext();) ... -
java中List集合的三种遍历实现 迭代器 普通for循环 增强for循环 使用时如何选择
2022-04-08 21:19:28遍历实现1.迭代器遍历2.普通for循环遍历2.增强for遍历 给出了如何选择遍历方式的些许建议