迭代时移除List中的元素的正确方式

一、简介

本篇文章总结一下另外一个很常见的错误:迭代的时候对集合对象进行删除操作的正确使用方式。

二、使用详解

如果遇到需要循环删除List中匹配的元素,相信很多小伙伴第一个想到的办法就是使用for循环遍历,然后使用挨个比较,如果相等则删除元素,即如下面的代码所示:

List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
for (int i = 0; i < list.size(); i++) {
    list.remove(i);
}
//[b, d]
System.out.println(list);

上面的代码应该是经常见到的,我们运行程序,发现结果输出为:

[b, d]

惊不惊喜意不意外,list居然没有全部删除掉,其实很多小伙伴们都犯过这种错误,为什么会出现这种情况呢?

当一个元素被移除时,该List的大小(size)就会缩减,同时也改变了索引的指向,也就是上面的代码只会循环两次,长度在不断减少,第一次循环0 < 4 ,第二次循环 1 < 3 ,不满足下一次循环条件 2 < 2,故只有两次循环就结束。所以,在迭代的过程中使用索引,将无法从List中正确地删除多个指定的元素。

那既然for循环不行,那我们换成foreach试试,代码如下:

List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
for (String str : list) {
    if ("a".equals(str)) {
        list.remove(str);
    }
}
System.out.println(list);

运行代码,很遗憾,报错了,如图:

麻蛋,为什么呢?

其实,在 foreach循环中,编译器使得 remove()方法先于next()方法被调用,这就导致了ConcurrentModificationException 异常,我们debug源码看一下,在下图位置抛出异常:

 

由此我们知道,正常情况下,next()方法必须在remove()方法之前被调用,这样才能正确移除元素,我们优化代码如下:

List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String next = iterator.next();
    if ("a".equals(next)) {
        iterator.remove();
    }
}
//[b, c, d]
System.out.println(list);

所以,这才是在循环中移除List元素的正确姿势。 明天圣诞节了,今晚平安夜,都吃苹果没,祝小伙伴们平安夜快乐呀。

移除list集合元素,可以使用以下几种方式方式一:使用迭代器Iterator。通过迭代器顺序向下遍历list,如果找到要移除元素,则使用remove方法进行移除。例如: ``` 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); ``` 方式二:倒序遍历list。通过for循环从最后一个元素开始倒序遍历list,如果找到要移除元素,则使用remove方法进行移除,并进行索引的自减操作。例如: ``` 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); ``` 方式三:正序遍历list。通过for循环从第一个元素开始正序遍历list,如果找到要移除元素,则使用remove方法进行移除,并进行索引的自减操作。例如: ``` 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); ``` 方式四:使用Stream流操作。通过使用jdk1.8新增的Stream流操作,可以使用filter方法将不需要移除元素筛选出来,从而得到移除元素后的list集合。例如: ``` List<String> list = new ArrayList<>(); list.add("赵云"); list.add("黄忠"); list.add("马超"); list.add("关羽"); list.add("张飞"); list = list.stream().filter(str -> !"关羽".equals(str)).collect(Collectors.toList()); System.out.println(list); ``` 以上是几种常用的移除list集合元素方式。根据具体需求,可以选择适合的方式进行操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [List移除元素的四种方式](https://blog.csdn.net/qq_58148854/article/details/131596870)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值