任何时候都不要在 for 循环中删除 List 集合元素!!!
首先说结论:无论什么场景,都不要对List使用for循环的同时,删除List集合元素,因为这么做就是不对的。
阿里开发手册也明确说明禁止使用foreach删除、增加List元素。
正确删除元素的方式是使用迭代器(Iterator),代码如下:
List<String> list = new ArrayList<>();
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {// 删除元素iterator.remove();
}
JDK8后lambda写法:
list.removeIf(s -> s.contains("a"));
不想知道为什么不能使用for循环删除List集合元素的,看完前言就可以关闭本页面了,想知道原因的继续往下看
下面举个实例场景,看一下为什么不能使用for循环。
需求
一个List集合,元素类型为String,有N个元素,删除这些元素中包含字符’‘a’'的元素。
假设集合内容如下:
List<String> list = new ArrayList<>(4);
list.add("a");
list.add("ab");
list.add("abc");
list.add("abcd");
public static void main(String[] args) {List<String> list = new ArrayList<>(4);list.add("a");list.add("ab");list.add("abc");list.add("abcd");Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {if (iterator.next().contains("a")) {// 删除元素iterator.remove();}}System.out.println(list);
}
输出结果为
[]
错误答案1:普通for循环(for-i)
public static void main(String[] args) {List<String> list = new ArrayList<>(4);list.add("a");list.add("ab");list.add("abc");list.add("abcd");for (int i = 0; i < list.size(); i++) {if (list.get(i).contains("a")) {list.remove(i);}}System.out.println(list);
}
输出结果为
[ab, abcd]
分析
普通for循环遍历List集合的同时,删除List中的元素是可以运行的代码,但在大多数场景下,不能使用这种方式,上边的结果也印证了这一点,虽然你的代码不会报错,运行也正常,但在本实例中,这么写就是BUG。
BUG原因:索引为i的元素删除后,后边元素的索引自动向前补位,即原来索引为i+1的元素,变为了索引为i的元素,但是下一次循环取的索引是i+1,此时你以为取到的是原来索引为i+1的元素,其实取到是原来索引为i+2的元素。
只要每删除一个元素,就会漏掉下一个元素,所以这种方式从逻辑上来说是存在bug的,无论什么需求场景,都不建议用这种方式,因为不可控因素太多(鬼知道生产环境中他会删掉多少元素,同时漏掉多少元素)。
既然这么写不报错,那么个别特殊场景确实可以使用这种普通for循环删除元素的,比如我们把实例的需求变动一下,改为:一个List集合,元素类型为String,有N个元素,删除这些元素中包含字符’a’的元素,如果有连续两个或以上元素包含’a’,那么只删除当前连续元素中的奇数位元素。虽然这种场景适用,但仍然不推荐,还是因为太不可控。
错误答案2:增强for循环(foreach)
public static void main(String[] args) {List<String> list = new ArrayList<>(4);list.add("a");list.add("ab");list.add("abc");list.add("abcd");for (String str : list) {if (str.contains("a")) {list.remove(str);}}System.out.println(list);
}
运行报错:
Exception in thread "main" java.util.ConcurrentModificationExceptionat java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)at java.util.ArrayList$Itr.next(ArrayList.java:859)at top.oldmoon.learn.test.ListTest.main(ListTest.java:24)
使用百度翻译可以知道:Concurrent Modification Exception:并发修改异常
分析
可以简单的理解为:foreach就不支持对集合中的元素进行增删操作,但是可以修改。
相关文章:
任何时候都不要在 for 循环中删除 List 集合元素!!!
首先说结论:无论什么场景,都不要对List使用for循环的同时,删除List集合元素,因为这么做就是不对的。 阿里开发手册也明确说明禁止使用foreach删除、增加List元素。 正确删除元素的方式是使用迭代器(Iteratorÿ…...
koa+Vite+vue3+ts+pinia构建项目
一、 初始化构建项目 npm create vite myProject -- --template vue-ts 注:Vite 需要 Node.js 版本 14.18,16。然而,有些模板需要依赖更高的 Node 版本才能正常运行,当你的包管理器发出警告时,请注意升级你的 Node 版…...

k8s-yaml文件
文章目录一、K8S支持的文件格式1、yaml和json的主要区别2、YAML语言格式二、YAML1、查看 API 资源版本标签2、编写资源配置清单2.1 编写 nginx-test.yaml 资源配置清单2.2 创建资源对象2.3 查看创建的pod资源3、创建service服务对外提供访问并测试3.1 编写nginx-svc-test.yaml文…...

存储引擎
目录 ❤ MySQL存储引擎 什么是存储引擎? MySQL支持哪个存储引擎? ❤ 各种存储引擎的特性 概述 各种存储引擎的特性 各种搜索引擎介绍 ❤ 常用存储引擎及适用场景 ❤ 存储引擎在mysql中的使用 存储引擎相关sql语句 指定存储引擎建表 在建表时指定 在配置文件中…...

Go中 channel的使用
文章目录背景channel 简介使用说明声明发送和接受数据关闭channel使用示例背景 使用 sync 包和 context 包的工具可以实现多个协程之间互相协作, 但是没有一种很好的方式解决多个协程之间通信的问题. golang 作者 Rob Pike 说过一句话,不要通过共享内存来通信&…...

【C++】string OJ练习
文章目录1. 仅仅反转字母思路分析代码实现2. 字符串中的第一个唯一字符题目分析代码实现3. 《剑指offer》——替换空格解法一:寻找替换思路分析代码实现优化解法二:空间换时间思路分析代码实现4.字符串最后一个单词的长度思路分析代码实现5. 字符串相加思…...

进程间通信IPC
进程间通信IPC (InterProcess Communication) 一、进程间通信的概念 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据…...

操作系统-页面淘汰算法(下)-软件设计(二十六)
操作系统-PV操作(上)-软件设计(二十五)https://blog.csdn.net/ke1ying/article/details/129476031 存储管理-分区存储组织 问:计算机系统内存大小为128k,当前系统分配情况如图,那么作业4再次申…...
23种设计模式-责任链模式(Android开发实际应用场景介绍)
什么是责任链模式 责任链模式是一种行为型设计模式,它的核心思想是将请求从一系列处理者中传递,直到其中一个处理者能够处理它为止。在这个过程中,请求可以被任何一个处理者处理,也可以被拒绝,直到有一个处理者能够处…...
Socket+Select+Epoll笔记
讲到epoll,就必须了解Socket,上篇博客写了Socket的基本使用方法,步骤主要为创建一个socketsocket是进程之间通信的,那么进程通信如何找到这个socket呢?当然是端口号,所以socket就要和端口号进行绑定&#x…...
git查看最近修改的文件
git log --name-status 每次修改的文件列表, 显示状态 git log --name-only 每次修改的文件列表 git log --stat 每次修改的文件列表, 及文件修改的统计 git whatchanged 每次修改的文件列表 git whatchanged --stat 每次修改的文件列表, 及文件修改的统计 git show 显示最…...
【算法基础(四)】堆排序(二)
堆排序(二) 把数组从零开始连续的一段 完全二叉树 size i 左 son 2*11 i 右 son 2*12 父 (i-1) / 2 堆是完全二叉树,分为大根堆和小根堆 在完全二叉树里,每一棵子数最大的值是头节点的值,就是大根堆 同理&…...
C++类型转换
C语言的转换是在变量前加类型名进行转换的,比如double pi 3.14;int a (int) pi;对于指针也是如此double* dptr πint* iptr (int*)dptr;虽然c兼容了C语言的转型方式,但是也做了很多限制,比如向上类型转换,在c中建议使用…...

Keil MDK6要来了,将嵌入式软件开发水平带到新高度,支持跨平台(2023-03-11)
注:这个是MDK6,不是MDK5 AC6,属于下一代MDK视频版: https://www.bilibili.com/video/BV16s4y157WF Keil MDK6要来了,将嵌入式软件开发水平带到新高度,支持跨平台一年一度的全球顶级嵌入式会展Embedded Wor…...

蓝桥杯刷题第九天
题目描述本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。素数就是不能再进行等分的整数。比如7,11。而 9 不是素数,因为它可以平分为 3 等份。一般认为最小的素数是2,接着是 3,5&…...

a-tree-select 基本使用,下拉框高度和宽度设置、回显时滚动条定位解决。
目录一、基本使用1. 界面效果2. 代码实现3. 问题1:下拉框占满整个屏幕4. 问题4:菜单内容过长时,下拉菜单宽度无限变宽。二、数据回显、滚动条定位1. 界面效果2. 代码实现2.1 获取默认展开节点2.1.1 代码实现2.1.2 说明2.2 设置滚动条定位2.2.…...

【Linux】之nc命令(连接与扫描指定端口、监测服务端口的使用情况)解析、详解实例、邮件告警
🍁博主简介 🏅云计算领域优质创作者 🏅华为云开发者社区专家博主 🏅阿里云开发者社区专家博主 💊交流社区:运维交流社区 欢迎大家的加入! 文章目录nc命令简介nc命令的安装nc命令语法格式…...

cdn简单配置
cdn配置域名接入CDN编辑CDN配置本地修改hosts文件,绕过公网解析域名接入CDN 添加CDN域名以及回源配置 编辑CDN配置 默认后端端口是80,如果测试发现无法访问,则可能是443或其它 如果域名在CDN后端有https强制跳转,后端端口一定是44…...

前端安全(自留)
目录XSS——跨站脚本常见解决CSRF ——跨站请求伪造常见解决XSS——跨站脚本 当目标站点在渲染html的过程中,遇到陌生的脚本指令执行。 攻击者通过在网站注入恶意脚本,使之在用户的浏览器上运行,从而盗取用户的信息如 cookie 等。 常见 解…...

零基础转行云计算可行吗
目前处于云年代,云计算运维工程师的工作远景还是十分广泛的。像是阿里云计算,滴滴,抖音等等互联网大厂目前都在使用云核算技能。 云计算运维工程师的薪资水平也十分可观。 运维工程师(Operations),在国内又称为运维开发工程师(Dev…...

SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

DBLP数据库是什么?
DBLP(Digital Bibliography & Library Project)Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高,数据库文献更新速度很快,很好地反映了国际计算机科学学术研…...