List--遍历时的错误用法
来源:互联网 发布:第十二个天体 知乎 编辑:程序博客网 时间:2024/06/06 03:40
作为Java大家庭中的集合类框架,List应该是平时开发中最常用的,可能有这种需求,当集合中的某些元素符合一定条件时,想要删除这个元素。如:
- public class ListTest {
- public static void main(String[] args) {
- List<Integer> intList = new ArrayList<Integer>();
- Collections.addAll(intList, 1, 2, 3, 5, 6);
- // for循环优化写法,只获取一次长度
- for(int i = 0, size = intList.size(); i < size; i++) {
- Integer value = intList.get(i);
- // 符合条件,删除元素
- if(value == 3 || value == 5) {
- intList.remove(i);
- }
- }
- System.out.println(intList);
- }
- }
public class ListTest { public static void main(String[] args) { List<Integer> intList = new ArrayList<Integer>(); Collections.addAll(intList, 1, 2, 3, 5, 6); // for循环优化写法,只获取一次长度 for(int i = 0, size = intList.size(); i < size; i++) { Integer value = intList.get(i); // 符合条件,删除元素 if(value == 3 || value == 5) { intList.remove(i); } } System.out.println(intList); }}执行后,会抛出IndexOutOfBoundsException,因为集合中存在符合条件的元素,删除后,集合长度动态改变,由于长度只获取一次,发生越界,所以,去掉for循环优化,如:
- public class ListTest {
- public static void main(String[] args) {
- List<Integer> intList = new ArrayList<Integer>();
- Collections.addAll(intList, 1, 2, 3, 5, 6);
- for(int i = 0; i < intList.size(); i++) {
- Integer value = intList.get(i);
- // 符合条件,删除元素
- if(value == 3 || value == 5) {
- intList.remove(i);
- }
- }
- System.out.println(intList);
- }
- }
public class ListTest { public static void main(String[] args) { List<Integer> intList = new ArrayList<Integer>(); Collections.addAll(intList, 1, 2, 3, 5, 6); for(int i = 0; i < intList.size(); i++) { Integer value = intList.get(i); // 符合条件,删除元素 if(value == 3 || value == 5) { intList.remove(i); } } System.out.println(intList); }}输出:[1, 2, 5, 6],漏掉了5这个元素,当i=2的时候,值为3,删除后,后面的元素往前补一位,这时i=3的时候,值为6,跳过了5,这样也不行,随后想到了用for循环增强,不显示的操作下标,直接操作对象,如:
- public class ListTest {
- public static void main(String[] args) {
- List<Integer> intList = new ArrayList<Integer>();
- Collections.addAll(intList, 1, 2, 3, 5, 6);
- for(Integer value : intList) {
- // 符合条件,删除元素
- if(value == 3 || value == 5) {
- intList.remove(value);
- }
- }
- System.out.println(intList);
- }
- }
public class ListTest { public static void main(String[] args) { List<Integer> intList = new ArrayList<Integer>(); Collections.addAll(intList, 1, 2, 3, 5, 6); for(Integer value : intList) { // 符合条件,删除元素 if(value == 3 || value == 5) { intList.remove(value); } } System.out.println(intList); }}执行后,会抛出ConcurrentModificationException,字面意思是并发修改异常。异常跟踪信息如下:
Exception inthread “main” java.util.ConcurrentModificationException
atjava.util.AbstractListItr.checkForComodification(AbstractList.java:449)</p><p> at java.util.AbstractListItr.next(AbstractList.java:420)
at ListTest.main(ListTest.java:13)
可以大概看出是执行到AbstractList中内部类Itr的checkForComodification方法抛出的异常,至于为什么出现异常,这里可以大概解释一下。集合遍历是使用Iterator, Iterator是工作在一个独立的线程中,并且拥有一个互斥锁。Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast原则 Iterator 会马上抛出java.util.ConcurrentModificationException 异常。所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。
而要解决这个问题,可以使用Iterator的remove方法,该方法会删除当前迭代对象的同时,维护索引的一致性。如:
- public class ListTest {
- public static void main(String[] args) {
- List<Integer> intList = new ArrayList<Integer>();
- Collections.addAll(intList, 1, 2, 3, 5, 6);
- Iterator<Integer> it = intList.iterator();
- while(it.hasNext()) {
- Integer value = it.next();
- if(value == 3 || value == 5) {
- it.remove();
- }
- }
- System.out.println(intList);
- }
- }
public class ListTest { public static void main(String[] args) { List<Integer> intList = new ArrayList<Integer>(); Collections.addAll(intList, 1, 2, 3, 5, 6); Iterator<Integer> it = intList.iterator(); while(it.hasNext()) { Integer value = it.next(); if(value == 3 || value == 5) { it.remove(); } } System.out.println(intList); }}输出正确结果:[1, 2, 6]。
不使用迭代器的解决方案就是,自己维护索引,删除一个元素后,索引-1,如:
- public class ListTest {
- public static void main(String[] args) {
- List<Integer> intList = new ArrayList<Integer>();
- Collections.addAll(intList, 1, 2, 3, 5, 6);
- for(int i = 0; i < intList.size(); i++) {
- Integer value = intList.get(i);
- if(value == 3 || value == 5) {
- intList.remove(i);
- i–;
- }
- }
- System.out.println(intList);
- }
- }
public class ListTest { public static void main(String[] args) { List<Integer> intList = new ArrayList<Integer>(); Collections.addAll(intList, 1, 2, 3, 5, 6); for(int i = 0; i < intList.size(); i++) { Integer value = intList.get(i); if(value == 3 || value == 5) { intList.remove(i); i--; } } System.out.println(intList); }}输出正确结果:[1, 2, 6]。
还有种取巧的方式是从最后一个元素开始遍历,符合条件的删除,如:
- public class ListTest {
- public static void main(String[] args) {
- List<Integer> intList = new ArrayList<Integer>();
- Collections.addAll(intList, 1, 2, 3, 5, 6);
- for(int i = intList.size() - 1; i >= 0; i–) {
- Integer value = intList.get(i);
- if(value == 3 || value == 5) {
- intList.remove(i);
- }
- }
- System.out.println(intList);
- }
- }
public class ListTest { public static void main(String[] args) { List<Integer> intList = new ArrayList<Integer>(); Collections.addAll(intList, 1, 2, 3, 5, 6); for(int i = intList.size() - 1; i >= 0; i--) { Integer value = intList.get(i); if(value == 3 || value == 5) { intList.remove(i); } } System.out.println(intList); }}输出正确结果:[1, 2, 6]。
最后,Java集合类框架真是大大方便了开发,不用自己去维护数组,随时担心着越界等问题。当然List的实现类对插入、删除的效率不太一样,这取决于其实现的数据结构,是选择删除,还是选择新建个集合,这里就不做讨论了。
本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/9347357。
- List--遍历时的错误用法
- List遍历时陷阱
- list遍历时删除元素
- c++下list在遍历时删除节点的方法
- python list遍历时删除元素的推荐做法
- js 截取字符串 list遍历时
- List,Set,Map遍历时删除元素
- hibernateTemplate.find方法的使用,查的list不是空,但是遍历时却是null
- 集合list在遍历时是不能做删除操作的
- c++中List在遍历时删除节点的方法,带源码
- c++中List在遍历时删除节点的方法(转载)
- vector, list, map在遍历时删除符合条件的元素
- std中vector和list容器遍历时元素的动态删除
- 数组遍历时遇到的小Bug
- 黄聪:C#使用能够foreach对hashtable、List遍历时“集合已修改;可能无法执行枚举操作。”错误
- JAVA中LISt遍历时如何remove元素
- 如何在遍历时删除List中的元素
- 使用ListIterator 对List遍历时修改,删除
- 容器的制作(Collation和Map)
- ORB-SLAM2在window下的配置 (3)
- 虚拟机工作原理
- 利用python创建学生管理系统软件代码赏析
- 安卓线布局与表格布局
- List--遍历时的错误用法
- MySQL存储引擎
- 微信公众号第三方平台开发 授权流程
- Review meeting还开不开?
- Windows+VS2013+GPU caffe 网络结构可视化亲自安装
- 《Java设计模式之装饰者模式》
- 数论倒数——逆元
- 冒泡法选择法排序
- Java内部类详解