JAVA中循环删除list中元素的方法总结

 循环删除list中的元素使用for循环的方式是有问题的,下面就来讲一讲。。

背景:业务中经常会涉及遍历list时对集合进行插入或者删除操作
一、 错误方式
先看看下面几段代码,1是foreach的方式去遍历list并删除元素,2是用迭代器的方式遍历list并删除元素,3是下标遍历
1. foreach 
 

public void testDel(){
List<Integer> list = Lists.newArrayList();
for(int i=1;i<=5;i++){
list.add(i);
}
for(Integer ele : list){
if(ele == 3)
list.remove(ele);
}
}

 


2. Iterator

public void testDel(){
List<Integer> list = Lists.newArrayList();
for(int i=1;i<=5;i++){
list.add(i);
}
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()){
Integer integer = iterator.next();
if(integer==3)
list.remove(integer);
}
}

 


以上两段代码的执行结果都是 java.util.ConcurrentModificationException。

在使用ArrayList时,当尝试用foreach或者Iterator遍历集合时进行删除或者插入元素的操作时,会抛出这样的异常:java.util.ConcurrentModificationException

关于这个异常的原因,看了很多文章,基本上解释如下:ArrayList的父类AbstarctList中有一个域modCount,每次对集合进行修改(增添、删除元素)时modCount都会+1。

而foreach的实现原理就是迭代器Iterator,在这里,迭代ArrayList的Iterator中有一个变量expectedModCount,该变量会初始化和modCount相等,但当对集合进行插入,删除操作,modCount会改变,就会造成expectedModCount!=modCount,此时就会抛出java.util.ConcurrentModificationException异常,是在checkForComodification方法中,代码如下:

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

 


那么,以上两种方式都不用呢,用下标遍历呢?看如下代码:

3 . 下标遍历

public void testDel() {
List<Integer> list = Lists.newArrayList();
list.add(1);
list.add(2);
list.add(2);
list.add(2);
list.add(2);
for(int i=0;i<list.size();i++){
if(list.get(i)==2){
list.remove(i);
}
}
}

 



//结果: list = [1,2,2]
因为下标是固定死的自增,但list的大小在随着删除元素不停的减小,并且后面的元素往前移了1位,所以后面的元素遍历不到。在i=3时,由于删了2个元素,size=3,所以循环直接结束。因此这种方式也是不符合预期的。

 
二、解决方法
但业务中经常涉及遍历时删除或插入操作。所以如何安全的操作ArrayList呢,解决方法如下!

1.使用迭代器的remove方法
在使用迭代器遍历时,可使用迭代器的remove方法,因为Iterator的remove方法中 有如下的操作:

expectedModCount = modCount;

所以避免了ConcurrentModificationException的异常。代码如下:

public void testDel() {
List<Integer> list = Lists.newArrayList();
list.add(1);
list.add(2);
list.add(2);
list.add(2);
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer integer = iterator.next();
if (integer == 2)
iterator.remove();
}
}

 



执行后结果: list = [1]
其实在阿里巴巴Java开发手册中原话:不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。

2.倒序遍历删除

public void testDel() {
List<Integer> list = Lists.newArrayList();
list.add(1);
list.add(2);
list.add(2);
list.add(2);
list.add(2);
for(int i=list.size()-1;i>=0;i--){
if(list.get(i)==2){
list.remove(i);
}
}
}

 


结果: list = [1]
可见,也达到了预期的效果。因为每次删除一个元素,list大小-1,但是倒序,循环条件为i>=0,所以list的size改变并没有对遍历造成影响,且元素的前移也不会对倒序遍历有影响。

 

其实JAVA中循环遍历list有三种方式for循环、增强for循环(也就是常说的foreach循环)、iterator遍历。

 

1、for循环遍历list

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

   这种方式的问题在于,删除某个元素后,list的大小发生了变化,而你的索引也在变化,所以会导致你在遍历的时候漏掉某些元素。比如当你删除第1个元素后,继续根据索引访问第2个元素时,因为删除的关系后面的元素都往前移动了一位,所以实际访问的是第3个元素。因此,这种方式可以用在删除特定的一个元素时使用,但不适合循环删除多个元素时使用。

 

2、增强for循环

for(String x:list){
    if(x.equals("del"))
        list.remove(x);
}

   这种方式的问题在于,删除元素后继续循环会报错误信息ConcurrentModificationException,因为元素在使用的时候发生了并发的修改,导致异常抛出。但是删除完毕马上使用break跳出,则不会触发报错。

 

3、iterator遍历

复制代码
Iterator<String> it = list.iterator();
while(it.hasNext()){
    String x = it.next();
    if(x.equals("del")){
        it.remove();
    }
}
复制代码

  这种方式可以正常的循环及删除。但要注意的是,使用iterator的remove方法,如果用list的remove方法同样会报上面提到的ConcurrentModificationException错误。

 

  总结:

  (1)循环删除list中特定一个元素的,可以使用三种方式中的任意一种,但在使用中要注意上面分析的各个问题。

  (2)循环删除list中多个元素的,应该使用迭代器iterator方式。

 

 

所以在对list或者hashmap遍历时候进行元素删增操作时,一定要验证下,我开始想当然的以为OK,调试才发现前面几种方式是有问题的,不是异常,就是效果没达到预期。到线上会出大问题。所以整理了下,推荐最后两种方式!

 

转载于:https://www.cnblogs.com/yhxb/p/11541863.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java,可以使用for循环删除List元素。以下是一种常见的方法: ```java List<String> list = new ArrayList<>(); list.add("del"); list.add("keep"); list.add("del"); list.add("keep"); for (int i = 0; i < list.size(); i++) { if (list.get(i).equals("del")) { list.remove(i); i--; // 因为删除元素后,后面的元素会向前移动,所以需要将索引减1 } } System.out.println(list.toString()); ``` 这段码会遍历List元素,如果元素的值等于"del",则使用List的remove方法将其删除。需要注意的是,在使用for循环遍历并删除List元素时,需要在删除元素后将索引减1,以防止跳过元素。输出结果将是`\[keep, keep\]`,即删除了所有值为"del"的元素。\[3\] #### 引用[.reference_title] - *1* [java循环删除List元素的3种方法](https://blog.csdn.net/guoqiaosen/article/details/108102397)[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^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Java循环删除List元素总结](https://blog.csdn.net/yaomingyang/article/details/78894799)[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^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [java循环 删除List某个元素](https://blog.csdn.net/qq_52524736/article/details/128306103)[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^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值