List移除元素的四种方式

news2024/9/20 14:48:47

List 移除某个元素

四种方式:

  • 方式一,使用 Iterator ,顺序向下,如果找到元素,则使用 remove 方法进行移除。
  • 方式二,倒序遍历 List ,如果找到元素,则使用 remove 方法进行移除。
  • 方式三,正序遍历 List ,如果找到元素,则使用 remove 方法进行移除,然后进行索引 “自减”。
  • 方式四,使用jdk1.8新增的Stream流操作
    1.Iterator 迭代器
	@Test
    public void fun9(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        // 获取迭代器
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String str = it.next();
            if("关羽".equals(str)){
                it.remove();
            }
        }
        System.out.println(list);
    }

2.倒序遍历

	@Test
    public void fun10(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (int i = list.size() - 1; i > 0; i--) {
            if("关羽".equals(list.get(i))){
                list.remove(i);
            }
        }
        System.out.println(list);
    }

3.正序遍历

 	@Test
    public void fun11(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (int i = 0; i < list.size(); i++) {
            if("关羽".equals(list.get(i))){
                list.remove(i);
                i--;
            }
        }
        System.out.println(list);
    }

4.Stream流操作(JDK 1.8 +)

	@Test
    public void fun8(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        // 筛选出不是“关羽” 的集合
        list = list.stream().filter(e -> !"关羽".equals(e)).collect(Collectors.toList());
        System.out.println("method4|list=" + list);

    }

问题:

1.为什么不能使用forEach

	@Test
    public void fun5(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (String str :list) {
            if ("张飞".equals(str)){
                list.remove(str);
            }
        }
        System.out.println(list);
    }

在这里插入图片描述
原因:
         foreach方式遍历元素的时候,是生成iterator,然后使用iterator遍历。在生成iterator的时候,会保存一个expectedModCount参数,这个是生成iterator的时候List中修改元素的次数。如果你在遍历过程中删除元素,List中modCount就会变化,如果这个modCount和exceptedModCount不一致,就会抛出异常。这个是为了安全的考虑。如果使用iterator遍历过程中,使用List修改了元素,可能会出现不正常的现象。如果使用iterator的remove方法则会正常,因为iterator的remove方法会在内部调用List的remove方法,但是会修改excepedModCount的值,因此会正常运行。

2.为什么forEach 删除倒数第二元素不会出现异常

 	@Test
    public void fun12() {
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (String str:list) {
            if("关羽".equals(str)){
                list.remove(str);
            }
            System.out.println(str);
        }
    }

在这里插入图片描述
仔细观察发现集合最后一个元素(“张飞”)并没有被遍历出来,因为当我们移除倒数第二个元素(“关羽”)时 cursor(游标)为 4 ,list 中size 属性的值会发生变化(5 - 1 = 4)变为 4,所以下面代码返回 false ,也就不会继续向下遍历。这也是能够正常执行的原因,因为如果继续遍历就会出现问题1 中的情况,在进行checkForComodification() 时,因为 modCount 发生了变化,而expectedModCount 并没有发生变化,所以会出现 ConcurrentModificationException异常。

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();
            }
        }
 public boolean hasNext() {
            return cursor != size;
        }
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();
        }

3 普通正序 for 循环为什么要 i –

因为遍历过程中进行remove 操作时,该位置后面的元素会挤到前面来,这时候会发生一种情况就是原来元素的位置会被他后面的元素取代,而该位置已经遍历过了,所以该元素不会背遍历。 所以要进行 i-- 操作从该位置重新遍历。

	@Test
    public void fun11(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
            if("关羽".equals(list.get(i))){
                list.remove(i);
            }
        }
        System.out.println(list);
    }

就是下面的情况 “张飞” 不见了…
在这里插入图片描述

4 为什么倒序for 循环可以

当我们倒序遍历元素的时候,无论删除元素之后的元素怎么移动,之前的元素对应的索引(index)是不会发生变化的,所以在删除元素的时候不会发生问题。

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

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

相关文章

使用TypeScript实现贪吃蛇小游戏(网页版)

本项目使用webpackts所编写 下边是项目的文件目录 /src下边的index.html页面是入口文件 index.ts是引入所有的ts文件 /modules文件夹是用来存放所有类的 index.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"…

VoxaMech 的机甲装备 — NFT 系列

一套新的机甲装备即将诞生&#xff1a;帝国甲虫套装是无与伦比的权威和威望的象征&#xff0c;体现了古代帝国甲虫的雄伟壮观。其华丽的铠甲散发着帝王般的优雅气息&#xff0c;其威严的外观在战场上令人肃然起敬。 每套装备由手臂部件、胸甲、头盔、腿部件和剑组成。每件装备单…

SpringBoot——业务层测试事务回滚

事务回滚 关于事务回滚的概念我们之前在学习数据库的时候已经提到过了&#xff0c;这里我们再次强化一下记忆。所谓的事务回滚就是在执行多条SQL语句的时候&#xff0c;如果其中一条SQL出现了异常导致执行失败&#xff0c;则数据库的状态回滚到执行多条SQL语句之前的状态&…

第六章:YOLO v1网络详解(统一的实时目标检测)

(目标检测篇&#xff09;系列文章目录 第一章:R-CNN网络详解 第二章:Fast R-CNN网络详解 第三章:Faster R-CNN网络详解 第四章:SSD网络详解 第五章:Mask R-CNN网络详解 第六章:YOLO v1网络详解 第七章:YOLO v2网络详解 第八章:YOLO v3网络详解 文章目录 系列文章目录技…

一起学SF框架系列5.7-模块Beans-BeanDefinition定义

在SF下&#xff0c;开发人员用xml或注解模式定义bean&#xff0c;框架把这些定义转化为内部BeanDefinition类&#xff0c;然后通过BeanDefinition类实现Bean的管理&#xff08;包括初始化、依赖注入及生命周期管理&#xff09;&#xff0c;因此了解Bean的定义、解析、使用过程非…

[kafka] windows下安装kafka(含安装包)

[kafka] windows下安装kafka&#xff08;含安装包&#xff09; 目录 前言 一、下载kafka安装包 1&#xff09;下载安装包 2&#xff09;解压安装包 二、运行zookeeper 1.运行zookeeper&#xff08;因为kafka必须要和zookeeper一起运行&#xff09; 三、运行kafka 四、使用fafka…

web3创业有哪些机会及具体案列(二)

目录 1. 去中心化金融&#xff08;DeFi&#xff09;&#xff1a;2. 去中心化身份验证和数字身份&#xff1a;3. 去中心化市场和电子商务&#xff1a;4. 区块链游戏和虚拟资产&#xff1a;5. 数据隐私和安全&#xff1a;6. 去中心化社交媒体&#xff1a;7. 去中心化能源交易&…

Spring容器扩展点在微服务中的使用

(20230306)Spring容器扩展点在微服务中的使用 文章目录 1. Spring扩展点梳理2.Spring扩展点应用场景2.1 整合NacosApplicationListener扩展场景——监听容器中发布的事件Lifecycle扩展场景——管理具有启动、停止生命周期需求的对象 2.2 整合RibbonSmartInitializingSingleton扩…

定时器中断实验(stm32)

目录 TIME的代码time.ctime.h main.c TIME的代码 time.c void TIM3_Int_Init(u16 arr,u16 psc) {TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能//定时器TIM3初始化…

uview u-input 点击清除按钮,数据清空但视图未清空

问题描述&#xff1a; 点击 uview 的 u-input 输入框自带的清除按钮&#xff0c;v-model 绑定的数据清空了&#xff0c;但是输入框内还显示着之前的数据 解决方案&#xff1a; 将 v-model 绑定的值写到 data 初始变量中声明 原始代码&#xff1a; <u-input v-model"…

Spring对事务的支持

目录 事务的传播行为 一、什么是事务的传播行为 二、7种事务传播行为 1. REQUIRED 2. REQUIRES_NEW 3. NESTED 4. 总结 三、事务的传播行为&#xff08;理解记忆&#xff09; 转载&#xff1a;一个99%的人都说不清楚知识点——Spring 事务传播行为 - 哔哩哔哩 事务属性…

2023.7.7HCIA中静态路由

一、题目要求 需求&#xff1a; 1.所有节点的IP地址均属于192.168.1.0 24--子网划分 2.全网可达--静态 3.加快收敛&#xff08;尽量汇总&#xff09; 5.R6存在环回接口--6.6.6.6 24&#xff0c;不能直接写去往6.6.6.0网段的路由--缺省 6.没有环路--NUll 0 7.正常流量走100M&am…

什么是ERC20?

ERC20 是以太坊区块链上最常见的代币标准之一。它是以太坊上智能合约的一种协议&#xff0c;定义了一套规则和接口&#xff0c;使得在以太坊网络上创建和管理代币变得更加简单和标准化。 ERC20 代币标准定义了一组功能和方法&#xff0c;以便代币合约可以与其他合约和钱包进行…

dxSpreadSheetReportDesigner使用笔记

通过该控件达到显示主从表,效果如下图所示. 在界面上放置以下控件 1.新建主从表主表为tab1,从表为tab2,二表通过设置从表的mastersource及MasterFields与从表联动. 2.设置dxspreadsheetreportdesigner与主从表关联 在DataBinding中的datasource关联主从. 在details中关联从表…

UE5、CesiumForUnreal接入XYZ格式地图瓦片如高德地图、OSM、ArcGIS等

文章目录 1.实现目标2.实现过程2.1 XYZ与TMS对比2.1 cesium-native改造2.3 CesiumForUnreal插件改造2.4 XYZ瓦片加载测试3.参考资料1.实现目标 通过改造cesium-native和cesiumforunreal插件,参考tms的栅格地图瓦片加载逻辑,实现在UE5、CesiumForUnreal中接入XYZ格式的地图瓦片…

-Xmx20m -Xms5m

-Xmsjava程序启动时初始堆的大小&#xff0c;默认是物理内存的1/64-Xmxjava程序能获得的最大堆的大小&#xff0c;默认为物理内存的1/4 验证默认值 winr → systeminfo 配置JVM启动参数&#xff1a;-XX:PrintCommandLineFlags-XX:ConcGCThreads3 -XX:G1ConcRefinementThreads…

UEditor v1.4.3.3 .net版本任意文件上传 漏洞复现

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 漏洞描述02 影响范围03 验证方式04 利用方式05 实战案例06 修复方案 01 漏洞描述 UEditor是一款所见即所得的开源富文本编辑器&#xff0c;具有轻量、可定制、用户体验优秀等特点&#xff0c;被广大…

flutter聊天界面-加号【➕】更多展开相机、相册等操作Panel

flutter聊天界面-加号【➕】更多展开相机、相册等操作Panel 在之前实现了flutter聊天界面的自定义表情的展示&#xff0c;这里记录一下更多操作展开的相机、相册等操作功能实现。 一、查看效果 更多操作展开的相机、相册等操作功能实现。 二、代码实现 展开的操作按钮可能比…

前端(四)——vue.js、vue、vue2、vue3

&#x1f60a;博主&#xff1a;小猫娃来啦 &#x1f60a;文章核心&#xff1a;vue.js、vue、vue2、vue3从全局到局部 文章目录 vue.js、vue、vue2、vue3是什么关系?Vue.js简介发展历程特点与优势生态系统Vue.js基础知识安装与配置 基本语法Vue.js主要版本解析Vue.js 2.x vue2…

python 第十一章 文件操作

系列文章目录 第一章 初识python 第二章 变量 第三章 基础语句 第四章 字符串str 第五章 列表list [] 第六章 元组tuple ( ) 第七章 字典dict {} 第八章 集合set {} 第九章 常用操作 第十章 函数 文章目录 系列文章目录11.1文件操作的作用11.2文件的基本操作打开打开文件模式 …