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());
}
}
输出的结果
此时很奇怪,为什么移除之后,值为11的元素还是存在呢?接下来我们来debug一下吧,先把断点打在第一个for循环那里,不断的向下进行,会出现以下情况。
当我们移除第一个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());
}
运行结果:
原因是这涉及多线程操作,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());
}
}
输出结果:
能成功的原因大概大家都已经知道了吧,不知道的话可以调试一下,尽管最后元素的前移,都不会影响到最后的输出结果,这也是一种解决的方案。
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());
}
输出结果
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());
}
输出结果:
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());
}
输出结果:
总结:
如果开发中需要在集合中移除某个元素,如果jdk是1.8的,建议直接使用2.4方法,如果是低版本,那么建议采用迭代器方法,效率高,性能好!