list删除数据有坑勿跳

有人看到这么标题可能觉得这个真是太easy了,不就remove吗,分分钟搞定。但结果却出乎意料,下面我们来说说list删除数据可能遇到的坑:

首先我们来初始化一个list

public static void main(String[] args) {
        ArrayList<String> list=new ArrayList<>();
        list.add("华为");
        list.add("中软");
        list.add("平安");
        list.add("富士康");
        list.add("富士康");
        list.add("软通");
        list.add("苏宁");
        System.out.println(list);

坑一:

我在list里添加一些各位大佬们以后要去的公司,突然想把里面的富士康删除掉。于是

	for (int i = 0; i < list.size(); i++) {
			if ("富士康".equals(list.get(i))) {
				list.remove(i);
			}
		}
		System.out.println(list);

结果输出:[华为, 中软, 平安, 富士康, 软通, 苏宁]

两个富士康还剩一个,不彻底嘛。原因很简单,就是List调用remove(index)方法后,会移除index位置上的元素,index之后的元素就全部依次左移。第二个"富士康"自然躲过一劫。

这时可以对索引同步调整下,代码如下:

    for (int i = 0; i < list.size(); i++) {
            if ("富士康".equals(list.get(i))) {
                list.remove(i--);
            }
        }

        System.out.println(list);

结果为:[华为, 中软, 平安, 软通, 苏宁]

坑二:

使用foreach遍历List删除元素,代码如下:

        for (String str : list) {
            if ("富士康".equals(str)) {
                list.remove(str);
            }
        }

        System.out.println(list);

结果如下:

Exception in thread "main" java.util.ConcurrentModificationException

居然报错,什么原因呢?其实foreach 是对的 Iterable、hasNext、next方法的简写。我们可以看看List.iterator()的源码:

private class Itr implements Iterator<E> {
        int cursor;       // 要返回的下一个元素的索引        int lastRet = -1; // 返回的最后一个元素的索引;如果没有就返回-1
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        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];
        }

        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();
            }
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

可以看出在 next、remove方法中都会调用checkForComodification 方法,该方法的作用是判断 modCount != expectedModCount是否相等,

如果不相等则抛出ConcurrentModificationException异常

当我们调用 list.remove(item)时,对 list 对象的 modCount 值进行了修改,

而 list 对象的迭代器的 expectedModCount 值未进行修改

所以就抛出ConcurrentModificationException异常!

但我们可以用迭代器来删除list数据,代码如下:

        Iterator<String> it=list.iterator();
        while(it.hasNext()){
            if("富士康".equals(it.next())){
                it.remove();
            }
        }

结果:[华为, 中软, 平安, 软通, 苏宁]

这是因为Iterator.remove() 方法会在删除当前迭代对象的同时,会保留原来元素的索引。

所以用迭代删除元素是最保险的方法,建议大家使用List过程中需要删除元素时,使用这种方式。

这里需要注意的是如果使用迭代器,用list.remove(str)方法删除元素,还是会抛ConcurrentModificationException异常。原因上面已经讲过!

总结:

1、用for循环遍历List删除元素时,需要注意索引会左移的问题。

2、List删除元素时,为避免陷阱,建议使用迭代器iterator的remove方式。

3、List删除元素时,默认按索引删除,而不是对象删除。

原文地址:https://www.cnblogs.com/zzjlxy-225223/p/11215732.html

时间: 2024-08-29 20:44:04

list删除数据有坑勿跳的相关文章

php处理登录、添加数据、删除数据和修改数据

php 处理登录 :需要先建一个登录的页面,用form表单就可以很轻松的完成,(这里的示例是我根据数据库现成的表做的 是一个teacher表格 根据老师的工号和姓名登录的) <form action="chuli.php" method="post"> <div> 工号: <input type="text" name="tno"/> </div> <div> 姓名:

MVC5 + EF6 + Bootstrap3 (13) 查看详情、编辑数据、删除数据

Slark.NET-博客园 http://www.cnblogs.com/slark/p/mvc5-ef6-bs3-get-started-rud.html 系列教程:MVC5 + EF6 + Bootstrap3 上一节:MVC5 + EF6 + Bootstrap3 (12) 新建数据 源码下载:点我下载 目录 前言 添加链接 查看详情 编辑数据 删除数据 结尾 前言 所谓万事开头难,前面用两节介绍了查询页面,一节介绍了创建数据.由于前面做了大量的铺垫,本节就能顺利的将查看详情.编辑数据.删

解决磁盘只读、介质受写入保护或者不能写入和删除数据的问题

我的硬盘有2块,一个固态,一个普通硬盘,最近普通硬盘被我莫名的搞成了只读甚至在格式化的时候还提示"介质受写入保护**",试了N多种方法都不行,最后还是在国外的网站上找到了解决方法,虽然我英文烂的很,可还是硬着头皮找到了.....现在记录下过程供遇到同种情况的伙伴参考.(另外说明下:国内的搜索简直无法直视,搜出的答案基本都是一个样!!注册表方法就不要尝试了,根本没用,我现在要说的是利用系统自带的diskpart命令进行解决.不知道U盘或者移动硬盘是否有效,反正大家可以试试.)PS:一定要

ODI中删除数据的处理

一.前提知识:数据从源数据库向数据仓库抽取时,一般采用以下几种方式: 全抽取模式如果表的数据量较小,则可以采取全表抽取方式,以TRUNCATE/INSERT方式进行数据抽取. 基于时间戳的抽取模式如果源数据表是不可更新的数据(如大多数事务处理数据)或者是不可删除数据(只能失效历史记录的情况),则根据变更时间戳,抽取最新变更的数据进行同步. 日志分析如果没有更新时间戳,或者源数据存在删除的情况,则可以进行日志分析,来执行最新数据变更的同步. 说明:时间戳的方式如果要处理删除数据的情况,需要在源表创

mysql优化, 删除数据后物理空间未释放(转载)

OPTIMIZE TABLE 当您的库中删除了大量的数据后,您可能会发现数据文件尺寸并没有减小.这是因为删除操作后在数据文件中留下碎片所致.OPTIMIZE TABLE 是指对表进行优化.如果已经删除了表的一大部分数据,或者如果已经对含有可变长度行的表(含有 VARCHAR . BLOB 或 TEXT 列的表)进行了很多更改,就应该使用 OPTIMIZE TABLE 命令来进行表优化.这个命令可以将表中的空间碎片进行合并,并且可以消除由于删除或者更新造成的空间浪费 .OPTIMIZE TABLE

PostgreSQL删除数据

到目前为止我们已经解释了如何向表中增加数据以及如何改变数据.剩下的是讨论如何删除不再需要的数据.和前面增加数据一样,删除数据也必须是从表中整行整行地删除.在上一节里我们提到了 SQL没有提供直接指定某一行的方法.因此,删除行只能是通过声明被删除行必须匹配的条件进行.如果你在表上有一个主键,那么你可以声明准确的行.当然,你也可以删除匹配条件的一组行,或者一次删除表中的所有行. 我们使用DELETE命令删除行.它的语法和UPDATE 命令非常类似.用: DELETE FROM Sites WHERE

第七章 插入、更新与删除数据

插入数据 1.为表左右字段插入数据 insert into 表名 values (值1,值2,……) 或 insert into 表名 (属性1,属性2,……) values (值1,值2……) 2.为指定字段插入数据 insert into 表名 (属性1,属性2,……) values (值1,值2……) 3.同时插入多条记录 insert into 表名 [(属性列表)] values(取值列表),(取值列表2),……: 4.将查询结果插入到表中 insert into 表名1 (属性列表1

解决sqlite删除数据后,文件大小不变问题(VACUUM)

删除表格的全部数据: DELETE FROM [Name] 当在sqlite中删除了大量数据后,数据库文件的大小还是那样,没有变.原因是:从Sqlite删除数据后,未使用的磁盘空间被添加到一个内在的”空闲列表”中用于存储你下次插入的数据.磁盘空间并没有丢失.但是也不向操作系统返回磁盘空间. 解决方法有以下两种:1,在数据删除后,手动执行SQL"VACUUM"命令,执行方式很简单.推荐使用.2,在数据库文件建成中,将auto_vacuum设置成“1”.但是第二个方法同样有缺点,只会从数据

ajax批量删除数据

做网页经常要选择批量删除数据,基本都是异步请求批量删除,用到更多的是ajax批量删除.思路是前端ajax请求,传入ids(要删除对象id的字符串数组)到后台. 后台再遍历id,调用删除接口,删除数据.返回json给前台. 代码例子如下: 1 function deleteSaleChance() { 2 var selectedRows = $("#dg").datagrid("getSelections"); 3 if(selectedRows.length==0