【Java】删除集合元素的正确与错误做法

news2024/9/23 5:32:18

错误做法

一、fori正序 + list.remove(num)

@Test  
public void test031(){  
    ArrayList<Integer> list = new ArrayList<>();  
    list.add(1);  
    list.add(3);  
    list.add(3);  
    for (int i = 0; i < list.size(); i++) {  
        Integer num=list.get(i);  
        if(num==3){  
            list.remove(num);  
        }  
    }  
    list.forEach(System.out::println);// 1 3  
}

image.png

我们可以看到,集合中有两个3,结果只删掉了第一个,原因是删除第一个3之后,第二个3的下标变成1,缺少了一次检查
image.png

改成方法:删除之后i–,回退一次,见下面的正确做法一

二、增强for + list.remove(num)

@Test  
public void test07(){  
    ArrayList<Integer> list = new ArrayList<>();  
    list.add(1);  
    list.add(3);  
    list.add(2);  
  
    for (Integer num:list) {  
        if(num==1){  
            list.remove(num);  
        }  
    }  
    list.forEach(System.out::println);  
}

image.png

我们看到报错的是ArrayList内部迭代器的next方法中的checkForCommdification方法抛出ConcurrentModificationException,源码如下

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];  
}
final void checkForComodification() { 
	
    if (modCount != expectedModCount)  
        throw new ConcurrentModificationException();  
}

我们可以看到modCount != expectedModCount,而抛出异常
原因是remove的时候修改了modCount,但是并未修改expectedModeCount

ArrayList的remove(Object o)的源码如下:

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;  
}  
  
/*  
 * Private remove method that skips bounds checking and does not * return the value removed. */
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  
}

修正方法:使用iteritor的remove(),见下面正确方法的三

正确做法

一、fori正序 + list.remove(num) + 回退

@Test  
public void test03(){  
    ArrayList<Integer> list = new ArrayList<>();  
    list.add(1);  
    list.add(3);  
    list.add(3);  
    for (int i = 0; i < list.size(); i++) {  
        Integer num=list.get(i);  
        if(num==3){  
            list.remove(num);  
            i--//注意回退,不然会缺少一次检查
        }  
    }  
    list.forEach(System.out::println);// 1 3  
}

二、fori倒序 + list.remove(num)

@Test  
public void test04(){  
    ArrayList<Integer> list = new ArrayList<>();  
    list.add(1);  
    list.add(3);  
    list.add(2);  
    for (int i = list.size()-1; i >=0; i--) {  
        Integer num=list.get(i);  
        if(num==1){  
            list.remove(num);  
        }  
    }  
    list.forEach(System.out::println);  
}

倒叙删除不用回退,如下图
image.png

三、iterator.remove()

@Test  
public void test01(){  
    ArrayList<Integer> list = new ArrayList<>();  
    list.add(1);  
    list.add(3);  
    list.add(2);  
    Iterator<Integer> iterator = list.iterator();  
    while (iterator.hasNext()){  
        Integer next = iterator.next();  
        if(next==3){  
            iterator.remove();  
        }  
    }  
    list.forEach(System.out::println);  
}

这种做法不会抛出ConcurrentModificationException的原因是,iterator.remove()也调用了remove(Object o),但是它把modCount的值,也赋值给了exceptionCount
源码如下:

public void remove() {  
    if (lastRet < 0)  
        throw new IllegalStateException();  
    checkForComodification();  
  
    try {  
        ArrayList.this.remove(lastRet);  
        cursor = lastRet;  
        lastRet = -1;  
        expectedModCount = modCount;  //这里
    } catch (IndexOutOfBoundsException ex) {  
        throw new ConcurrentModificationException();  
    }  
}

四、list.removeIf(条件)

@Test  
public void test02(){  
    ArrayList<Integer> list = new ArrayList<>();  
    list.add(1);  
    list.add(3);  
    list.add(3);  
    list.removeIf(next -> next == 3);  
    list.forEach(System.out::println);  
}

注意事项

  • remove有两个重载方法,一个接收int的index,一个接收Object的o,注意不要写错

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/735604.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据集 VOC转YOLO格式

一、xml转换为txt import os.path import xml.etree.ElementTree as ET import os import random # class_names [palm, stone, scissor, awesome, heartB, OK, ROCK, one, swear, thanks, heartA, # heartC, good, bad, pray, call, take_picture, salute] c…

Java:缓冲流

1.缓冲流分类 2.字节缓冲流 原理:底层自带了长度为8192的缓冲区提高性能。 1.方法&#xff1a; public BufferedInputstream( Inputstream is)&#xff1a;把基本流包装成高级流&#xff0c;提高读取数据的性能。public BufferedOutputStream(OutputStream os)把基本流包装成…

【Java|基础篇】面向对象三大特性之继承(上)

文章目录 1. 前言2. 问题提出3. 什么是继承4. 继承的特点 1. 前言 继承是面向对象三大特性之一. Java的继承也是很复杂. 本篇文章先帮助大家理解继承的概念 2. 问题提出 先来看这两个类: Student类: public class Student {private String name;private int age;private S…

【技能实训】DMS数据挖掘项目-Day02

文章目录 任务3【任务3.1】实现日志实体类【任务3.2】创建日志业务类&#xff0c;实现日志信息的采集及打印输出【任务3.3】创建日志测试类&#xff0c;测试任务3.2中的程序&#xff0c;演示日志信息的采集及打印输出 任务4【任务4.1】物流实体信息类【任务4.2】创建物流业务类…

Slicer学习笔记(六十四) 关于3DSlicer的python脚本和编程

Slicer学习笔记(六十四) 关于3DSlicer的python脚本和编程 目标1. 软件结构2. 在Slicer中使用python控制台 简单的脚本模块示例3. 单独编写简单的脚本模块目标 1. 软件结构 Slicer应用程序架构 模块类型:c++可加载 模块类型:脚本加载 模块类型:CLI Slicer数据模型 MRML

SendGrid 无法注册,Create Account 按钮灰色无法点击

问题描述&#xff1a; 注册SendGrid的时候&#xff0c;账号密码都输好了&#xff0c;就是没办法点【Create Account】。 解释思路&#xff1a; 其实空白处有一个reCAPTCHA 验证码&#xff0c;但是被隐去了。所以我们的思路是如何让网页中的reCAPTCHA 验证码顺利显示出来。 问…

vue实现一个购物车全功能

效果图: 1.静态代码结构渲染 <div class"app-container" id"app"><!-- 顶部banner --><div class"banner-box"><img src"http://autumnfish.cn/static/fruit.jpg" alt"" /></div><!-- 面包…

了解个人所得税

文章目录 1 个人所得税1.1 前置知识&#xff08;一定多看几遍&#xff09;1.2 个人所得税计算 2 汇算清缴参考 1 个人所得税 1.1 前置知识&#xff08;一定多看几遍&#xff09; 首先我们要弄清楚几个概念&#xff1a; ① 应纳税所得额 综合所得额 - 免征 - 扣除 ② 综合所…

Selenium浏览器自动化测试框架简单介绍

目录 selenium简介 介绍 功能 优势 基本使用 获取单节点 获取多节点 节点交互 动作链 执行JavaScript代码 获取节点信息 切换frame 延时等待 前进和后退 cookies 选项卡管理 异常处理 选项卡切换 无头浏览器 selenium简介 介绍 Selenium [1] 是一个用于We…

VectorCAST软件的License 配置

一、配置 License 服务 进入 VectorCAST 安装目录&#xff08;默认为 C:\VCAST&#xff0c;如果在安装时修改了安装路径&#xff0c;在这里需要进入对 应的安装目录&#xff09;&#xff0c;找到 FLEXlm 文件夹&#xff0c;将 License 文件复制到 FLEXlm 文件夹下面。运行 lmt…

当你按下键盘A键

CPU 里面的内存接口&#xff0c;直接和系统总线通信&#xff0c;然后系统总线再接入一个 I/O 桥接器&#xff0c;这个 I/O 桥接器&#xff0c;另一边接入了内存总线&#xff0c;使得 CPU 和内存通信。再另一边&#xff0c;又接入了一个 I/O 总线&#xff0c;用来连接 I/O 设备&…

视图与索引的详细用法

视图与索引的详细用法 1.视图的主要作用包括&#xff1a;1.简化查询&#xff1a;2.数据安全性&#xff1a;3.数据抽象&#xff1a; 2.索引简介1.索引的作用主要有以下几个方面&#xff1a;1.快速定位数&#xff1a;2. 提高查询性能3.加速排序和连接操作4.维护数据完整性 3.索引…

文字和祝福语:创意的粒子效果网页(❤️好看好用❤️)HTML+CSS+JS

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

Flink DataStream之Union合并流

新建类 package test01;import jdk.nashorn.internal.runtime.regexp.joni.Config; import org.apache.flink.api.java.ExecutionEnvironment; import org.apache.flink.configuration.Configuration; import org.apache.flink.streaming.api.datastream.DataStream; import o…

【SpringBoot3】--01.快速入门、基本框架原理、常用注解、yaml配置文件、日志配置

文章目录 SpringBoot3核心特性1.简介1. 1前置知识1.2 环境要求1.3SpringBoot是什么 2.快速入门2.1开发流程2.1.1创建项目2.1.2导入场景2.1.3 主程序2.1.4 业务2.1.5 测试2.1.6 打包 2.2 特性小结2.2.1 简化整合2.2.2简化开发2.2.3 简化配置2.2.4 简化部署2.2.5 简化运维 2.3 Sp…

iOS通用链接(UniversalLink)配置详细流程

一、Universal Links 配置过程 登录苹果账号后&#xff0c;点击创建的APP 的Bundle ID&#xff0c;跳转到APP 信息页面。记录下Team ID 和Bundle ID 备用。勾选上 功能列表上的 ”Associated Domains“选项。 配置苹果后台 创建一个text空文本文件&#xff0c;去掉文件后缀&a…

【Linux | Shell】构建基础脚本 - 读书笔记

目录 一、创建第一个Shell脚本1.1 执行多个命令1.2 创建 shell 脚本1.2.1 指定使用的shell1.2.2 在脚本文件各行输入命令1.2.3 添加执行权限1.2.4 执行脚本 1.3 显示消息——echo命令 二、使用变量2.1 三四五 一、创建第一个Shell脚本 前面得文章介绍过一些基础的 Linux 命令了…

【InnoDB 存储引擎】5.4.5 The Slow Query Log(慢日志实验, 详细描述了与 MySQL 相关的慢日志方方面面)

文章目录 1 慢日志实验环境准备2 开始实验2.1 实验 1&#xff1a;超过查询时间相关慢日志并观察2.2 实验 2&#xff1a;不使用索引相关慢日志并观察2.3 实验 3&#xff1a;打印额外的慢日志信息2.4 实验 4&#xff1a;使用 mysqldumpslow 工具分析日志文件2.5 实验 5&#xff1…

【雕爷学编程】Arduino动手做(153)---2.4寸TFT液晶触摸屏模块5

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

【计算机组成与体系结构Ⅰ】实验5 CPU组成与机器指令执行实验

一、实验目的 1&#xff1a;将微程序控制器同执行部件&#xff08;整个数据通路&#xff09;联机&#xff0c;组成一台模型计算机。 2&#xff1a;用微程序控制器控制模型机数据通路。 3&#xff1a;通过CPU运行几条机器指令&#xff08;排除中断指令&#xff09;组成的简单…