List集合中的remove元素

List集合中的remove元素

1.通常,我们会进行一个for循环,然后想要移除的元素与循环的元素进行一个对比,此时如果他们的值相等,就把此时循环到的那个值相等的元素进行移除,这是我们最基本的思路,但是,List集合是可重复的,还有我们的for循环是否在某些是否会存在一些Bug呢?

下面我们先上代码

package com.example.demo;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class listRemove {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("11");
        list.add("11");
        list.add("12");
        list.add("13");
        list.add("14");
        list.add("15");
        list.add("16");
        System.out.println("原始list元素:"+ list.toString());
        CopyOnWriteArrayList<String> copyList = new CopyOnWriteArrayList<>(list);


        for (int i = 0; i < list.size(); i++) {
            String item = list.get(i);
            if("11".equals(item)) {
                list.remove(i);
            }
        }
        System.out.println("通过下表移除后的list元素:"+ list.toString());

        //通过对象移除等于11的元素
        for (int i = 0; i < copyList.size(); i++) {
            String item = copyList.get(i);
            if("11".equals(item)) {
                copyList.remove(item);
            }
        }
        System.out.println("通过对象移除后的list元素:"+ list.toString());
    }
}

输出的结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aIDX3G1E-1612510429952)(C:\Users\Fujiseiko\AppData\Roaming\Typora\typora-user-images\image-20210205151156145.png)]

此时很奇怪,为什么移除之后,值为11的元素还是存在呢?接下来我们来debug一下吧,先把断点打在第一个for循环那里,不断的向下进行,会出现以下情况。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M03iWT2l-1612510429954)(C:\Users\Fujiseiko\AppData\Roaming\Typora\typora-user-images\image-20210205151413054.png)]

当我们移除第一个List元素之后呢,size是变成6,此时第二个item=11的下标已经在i=0的位置了,因为所有的元素都向前移动了一位,但是此时的i已经是++了,所以i=1时,item等于12了,所以才会导致第二个item删除不到的情况。

2.我们进行foreach的情况是怎样的呢?

public static void main(String[] args) {
	List<String> list = new ArrayList<String>();
	list.add("11");
	list.add("11");
	list.add("12");
	list.add("13");
	list.add("14");
	list.add("15");
	list.add("16");
	System.out.println("原始list元素:"+ list.toString());
	
	
	//通过对象移除等于11的元素
	for (String item : list) {
		if("11".equals(item)) {
			list.remove(item);
		}
	}
	System.out.println("通过对象移除后的list元素:"+ list.toString());
	
}

运行结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-thtSWGBh-1612510429956)(C:\Users\Fujiseiko\AppData\Roaming\Typora\typora-user-images\image-20210205151732902.png)]

原因是这涉及多线程操作,Iterator是不支持多线程操作的,List类会在内部维护一个modCount的变量,用来记录修改次数。

详细讲解请看江南小码哥的java基础系列文章。这里就不再做详细的解释了。

3.解决方法

采用倒叙的方式

package com.example.demo;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class listSolve {
        public static void main(String[] args) {
            List<String> list = new ArrayList<String>();
            list.add("11");
            list.add("11");
            list.add("12");
            list.add("13");
            list.add("14");
            list.add("15");
            list.add("16");
            System.out.println("原始list元素:"+ list.toString());
            CopyOnWriteArrayList<String> copyList = new CopyOnWriteArrayList<>(list);

            //通过下表移除等于11的元素
            for (int i = list.size() - 1; i >= 0; i--) {
                String item = list.get(i);
                if("11".equals(item)) {
                    list.remove(i);
                }
            }
            System.out.println("通过下表移除后的list元素:"+ list.toString());

            //通过对象移除等于11的元素
            for (int i = copyList.size() - 1; i >= 0; i--) {
                String item = copyList.get(i);
                if("11".equals(item)) {
                    copyList.remove(item);
                }
            }
            System.out.println("通过对象移除后的list元素:"+ list.toString());

        }
    }

输出结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HQvVBF8M-1612510429958)(C:\Users\Fujiseiko\AppData\Roaming\Typora\typora-user-images\image-20210205152328040.png)]

能成功的原因大概大家都已经知道了吧,不知道的话可以调试一下,尽管最后元素的前移,都不会影响到最后的输出结果,这也是一种解决的方案。

4.第二种方案

public static void main(String[] args) {
	List<String> list = new ArrayList<String>();
	list.add("11");
	list.add("11");
	list.add("12");
	list.add("13");
	list.add("14");
	list.add("15");
	list.add("16");
	System.out.println("原始list元素:"+ list.toString());
	CopyOnWriteArrayList<String> copyList = new CopyOnWriteArrayList<>(list);
	
	//通过对象移除等于11的元素
	for (String item : copyList) {
		if("11".equals(item)) {
			copyList.remove(item);
		}
	}
	System.out.println("通过对象移除后的list元素:"+ copyList.toString());
	
}

输出结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ozdizj3R-1612510429958)(C:\Users\Fujiseiko\AppData\Roaming\Typora\typora-user-images\image-20210205153026799.png)]

5.第三种解决方案,利用迭代器去删除

public static void main(String[] args) {
	List<String> list = new ArrayList<String>();
	list.add("11");
	list.add("11");
	list.add("12");
	list.add("13");
	list.add("14");
	list.add("15");
	list.add("16");
	System.out.println("原始list元素:"+ list.toString());
	
	//通过迭代器移除等于11的元素
	Iterator<String> iterator = list.iterator();
	while(iterator.hasNext()) {
		String item = iterator.next();
		if("11".equals(item)) {
			iterator.remove();
		}
	}
	System.out.println("通过迭代器移除后的list元素:"+ list.toString());
	
}

输出结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yx1usAGu-1612510429959)(C:\Users\Fujiseiko\AppData\Roaming\Typora\typora-user-images\image-20210205153124578.png)]

6.第四种解决方案,利用jdk1.8特性去删除

public static void main(String[] args) {
	List<String> list = new ArrayList<String>();
	list.add("11");
	list.add("11");
	list.add("12");
	list.add("13");
	list.add("14");
	list.add("15");
	list.add("16");
	System.out.println("原始list元素:"+ list.toString());
	
	//jdk1.8移除等于11的元素
	list.removeIf(item -> "11".equals(item));
	System.out.println("移除后的list元素:"+ list.toString());
	
}

输出结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JLEm8uYX-1612510429960)(C:\Users\Fujiseiko\AppData\Roaming\Typora\typora-user-images\image-20210205153124578.png)]

总结:

如果开发中需要在集合中移除某个元素,如果jdk是1.8的,建议直接使用2.4方法,如果是低版本,那么建议采用迭代器方法,效率高,性能好!

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值