Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >如何正确遍历删除List中的元素(普通for循环、增强for循环、迭代器iterator、removeIf+方法引用)

如何正确遍历删除List中的元素(普通for循环、增强for循环、迭代器iterator、removeIf+方法引用)

作者头像
崔笑颜
发布于 2020-06-08 08:30:54
发布于 2020-06-08 08:30:54
12.3K02
代码可运行
举报
运行总次数:2
代码可运行

遍历删除List中符合条件的元素主要有以下几种方法:

  1. 普通for循环 2.增强for循环 foreach 3.迭代器iterator 4.removeIf 和 方法引用 (一行代码搞定) 其中使用普通for循环容易造成遗漏元素的问题,增强for循环foreach会报java.util.ConcurrentModificationException并发修改异常。

所以推荐使用迭代器iterator,或者JDK1.8以上使用lambda表达式进行List的遍历删除元素操作。

以下是上述几种方法的具体分析:

普通for循环

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** 
 * 普通for循环遍历删除元素
 */  
    List<Student> students = this.getStudents();  
    for (int i=0; i<students.size(); i++) {  
        if (students.get(i).getId()%3 == 0) {  
            Student student = students.get(i);  
            students.remove(student);  
        }  
    }

由于在循环中删除元素后,list的索引会自动变化,list.size()获取到的list长度也会实时更新,所以会造成漏掉被删除元素后一个索引的元素。

比如循环到第2个元素时你把它删了,接下来去访问第3个元素,实际上访问到的是原来list的第4个元素,因为原来的第3个元素变成了现在的第2个元素。这样就造成了元素的遗漏。

增强for循环 foreach

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 增强for循环遍历删除元素
 */
    List<Student> students = this.getStudents();  
    for (Student stu : students) {  
        if (stu.getId() == 2)   
            students.remove(stu);  
    }

使用foreach遍历循环删除符合条件的元素,不会出现普通for循环的遗漏元素问题,但是会产生java.util.ConcurrentModificationException并发修改异常的错误。

报ConcurrentModificationException错误的原因:

  先来看一下JDK源码中ArrayList的remove源码是怎么实现的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

一般情况下程序的执行路径会走到else路径下最终调用fastRemove方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }

在fastRemove方法中,可以看到第2行把modCount变量的值加一,但在ArrayList返回的迭代器会做迭代器内部的修改次数检查:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
final void checkForComodification() {
         if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
     }

而foreach写法是对实际的Iterable、hasNext、next方法的简写,因为上面的remove(Object)方法修改了modCount的值,所以才会报出并发修改异常。

要避免这种情况的出现则在使用迭代器迭代时(显式或for-each的隐式)不要使用List的remove,改为用Iterator的remove即可。

迭代器iterator

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 *  迭代器iterator
 */
     List<Student> students = this.getStudents();  
     System.out.println(students);  
     Iterator<Student> iterator = students.iterator();  
     while (iterator .hasNext()) {  
         Student student = iterator .next();  
         if (iterator.getId() % 2 == 0)  
             iterator.remove();//这里要使用Iterator的remove方法移除当前对象,如果使用List的remove方法,则同样会出现ConcurrentModificationException  
     }

由上述foreach报错的原因,注意要使用迭代器的remove方法,而不是List的remove方法。

removeIf 和 方法引用

在JDK1.8中,Collection以及其子类新加入了removeIf方法,作用是按照一定规则过滤集合中的元素。

方法引用是也是JDK1.8的新特性之一。方法引用通过方法的名字来指向一个方法,使用一对冒号 :: 来完成对方法的调用,可以使语言的构造更紧凑简洁,减少冗余代码。

使用removeIf和方法引用删除List中符合条件的元素:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
List<String> urls = this.getUrls();  

// 使用方法引用删除urls中值为"null"的元素
urls.removeIf("null"::equals);

作为removeIf的条件,为true时就删除元素。

使用removeIf 和 方法引用,可以将原本需要七八行的代码,缩减到一行即可完成,使代码的构造更紧凑简洁,减少冗余代码。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
为什么Iterator的remove方法可保证从源集合中安全地删除对象,而在迭代期间不能直接删除集合内元素
https://blog.csdn.net/yanshuanche3765/article/details/78917507
挨踢小子部落阁
2020/01/15
5.9K1
ArrayList源码完全分析
本文介绍了Java中的ArrayList类,它是Java编程语言中最常用的集合类之一。ArrayList用于存储一系列元素,允许添加、删除和随机访问元素。ArrayList的底层实现是数组,它通过ArrayList的实例变量来存储元素。在ArrayList中,添加、删除和随机访问元素的时间复杂度分别是O(1)、O(1)和O(1)。ArrayList的常用方法有add、remove、set、get、size、iterator、listIterator等。同时,文章还对ArrayList的性能、容量预估、扩容、元素访问顺序等方面进行了详细阐述。
MelonTeam
2018/01/04
9670
理解分析java集合操作之ConcurrentModificationException
首先我们知道增强for循环其实现原理就是Iterator接口,这一点非常重要,有了个这个知识点 我们才能分析为什么会出现异常,这个知识点也是最重要最核心的。
XING辋
2019/03/26
7160
【Java面试题】List如何一边遍历,一边删除?该如何回答?
然后满怀信心的去运行,结果竟然抛java.util.ConcurrentModificationException异常了,翻译成中文就是:并发修改异常。
用户2242639
2021/06/29
6120
Java容器 ArrayList
ArrayList 数组容器类,实现了List,RandomAccess,Cloneable,Serializable四个接口,继承自AbstractList,具有动态扩容,随机访问,可复制,可序列化四个主要功能。
zeody
2019/05/15
6360
Java容器 ArrayList
《我们一起学集合》-ArrayList
今天我们要研究的集合是ArrayList,在我们学习ArrayList之前,我们先看看面试官是如何利用ArrayList的相关知识点来吊打我们得。
蚊子
2021/01/27
4840
《我们一起学集合》-ArrayList
ArrayList的删除姿势你都知道了吗
前几天有个读者由于看了《ArrayList哪种遍历效率最好,你真的弄明白了吗?》问了个问题普通for循环ArrayList为什么不能删除连续重复的两个元素?其实这个描述是不正确的。正确的应该是普通for循环正序删除,不能删除连续的元素所以就产生了这个文章。
java金融
2020/06/23
8300
ArrayList的删除姿势你都知道了吗
ArrayList的删除姿势你都掌握了吗
前几天有个读者由于看了《ArrayList哪种遍历效率最好,你真的弄明白了吗?》问了个问题普通for循环ArrayList为什么不能删除连续重复的两个元素?其实这个描述是不正确的。正确的应该是普通for循环正序删除,不能删除连续的元素所以就产生了这个文章。
java金融
2020/08/05
5460
ArrayList的删除姿势你都掌握了吗
还在自己写迭代器进行remove?快来看看新方法
我们都知道 List 中是不允许在循环的过程中去进行移除元素的,为什么呢?一般的新人可能会遇到这个问题,比如说会从 List 的遍历的过程中去进行 remove 数据,但是干过几年的开发的有经验的工作人员,是肯定不会这么干的,很简单,会报错。
Java极客技术
2022/12/04
2420
还在自己写迭代器进行remove?快来看看新方法
Java|如何正确地在遍历 List 时删除元素
最近在一个 Android 项目里遇到一个偶现的 java.util.ConcurrentModificationException 异常导致的崩溃,经过排查,导致异常的代码大概是这样的:
mzlogin
2024/04/30
2600
已解决Java中java.util.ConcurrentModificationException异常
成功解决Java ConcurrentModificationException异常
程序员洲洲
2024/06/07
1130
Java Iterator(迭代器)小笔记
Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法,可用于迭代 ArrayList和 HashSet 等集合。Iterator 是 Java 迭代器最简单的实现,ListIterator 是 Collection API 中的接口, 它扩展了 Iterator 接口。
joshua317
2022/03/29
5800
Java Iterator(迭代器)小笔记
并发修改异常ConcurrentModificationException详解
在多线程编程中,相信很多小伙伴都遇到过并发修改异常ConcurrentModificationException,本篇文章我们就来讲解并发修改异常的现象以及分析一下它是如何产生的。
终有救赎
2023/10/22
7580
并发修改异常ConcurrentModificationException详解
遍历删除List中的元素
遍历删除List中的元素有很多种方法,当运用不当的时候就会产生问题。下面主要看看以下几种遍历删除List中元素的形式: 1.通过增强的for循环删除符合条件的多个元素 2.通过增强的for循环删除符合条件的一个元素 3.通过普通的for删除删除符合条件的多个元素 4.通过Iterator进行遍历删除符合条件的多个元素 Java代码 /** * 使用增强的for循环 * 在循环过程中从List中删除元素以后,继续循环List时会报ConcurrentModificationException
java达人
2018/01/31
4.7K0
遍历数据时arraylist效率高于linkedlist_遍历问题种类
一个 java 程序猿比较广为人知的小知识 ,是 ArrayList 和 LinkedList 最好使用迭代器删除,而不是遍历删除。
全栈程序员站长
2022/09/23
6860
遍历数据时arraylist效率高于linkedlist_遍历问题种类
ArrayList 源码分析
在 Java 中当创建数组时会在内存中划分一块连续的内存,然后当有数据进入的时候会将数据按顺序的存储在这块连续的内存中。当需要读取数组中的数据时,需要提供数组中的索引,然后数组根据索引将内存中的数据取出来,返回给读取程序。在 Java 中并不是所有的数据都能存储到数组中,只有相同类型的数据才可以一起存储到数组中。
希希里之海
2019/09/05
4690
List中remove()方法的陷阱,被坑惨了!
Java的List在删除元素时,一般会用list.remove(o)/remove(i)方法。在使用时,容易触碰陷阱,得到意想不到的结果。总结以往经验,记录下来与大家分享。
好好学java
2021/10/09
6280
Java,你告诉我 fail-fast 是什么鬼?
说起来真特么惭愧:十年 IT 老兵,Java 菜鸟一枚。今天我才了解到 Java 还有 fail-fast 一说。不得不感慨啊,学习真的是没有止境。只要肯学,就会有巨多巨多别人眼中的“旧”知识涌现出来,并且在我这全是新的。
Java技术江湖
2019/11/11
4790
Java,你告诉我 fail-fast 是什么鬼?
ArrayList分析3 : 删除元素
转载请注明出处:https://www.cnblogs.com/funnyzpc/p/16421743.html
上帝
2022/07/09
2860
ArrayList边遍历边删除?
一个for循环遍历,如果item > 2就执行remove,看上去似乎没有问题的样子,也不会出现报错,但是不符合题目的要求
DH镔
2019/12/19
1.8K0
相关推荐
为什么Iterator的remove方法可保证从源集合中安全地删除对象,而在迭代期间不能直接删除集合内元素
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文