1.list的 remove 方法
在实际业务中有很多需要筛选的需求,写代码时常常用List 的 remove 方法来移除不符的数据,但是 remove 方法是很多程序员容易犯的错。开门见山,见代码:
public static void main(String[] args) {
Student stu1 = new Student();
stu1.setAge("16");
stu1.setName("张萌");
stu1.setSex("女");
Student stu2 = new Student();
stu2.setAge("20");
stu2.setName("张帅");
stu2.setSex("男");
List<Student> list1 = new ArrayList<>();
list1.add(stu1);
list1.add(stu2);
Student stu4 = new Student();
stu4.setAge("16");
stu4.setName("张萌meng");
stu4.setSex("女");
Student stu5 = new Student();
stu5.setAge("28");
stu5.setName("赵帅");
stu5.setSex("男");
Student stu6 = new Student();
stu6.setAge("27");
stu6.setName("赵亮");
stu6.setSex("男");
List<Student> list2 = new ArrayList<>();
list2.add(stu4);
list2.add(stu5);
list2.add(stu6);
screenData(list1, list2);
System.out.println(JSON.toJSONString(list2));
}
/**
* 移除不符合的数据
* */
public static void screenData(List<Student> list1, List<Student> list2){
for(Student s1 : list1){
for(Student s2 : list2){
//将年龄相等的数据移除
if(s1.getAge().equals(s2.getAge())){
list2.remove(s2);
}
}
}
}
代码行云流水的写出来,一运行就抓头
报 java.util.ConcurrentModificationException 异常,我们来分析一下原因:
报错在:at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911) 看一下list的源码发现是 checkForComodification() 方法为 ArrayList 内部类Itr的一个方法 ,当modCount != expectedModCount 时会抛出异常ConcurrentModificationException。
先来解释下概念:
modCount:为 成员变量 list 被修改的次数 ,每次add ,remove都会+1 (The number of times this list has been )
expectedModCount:为listIterator 方法 局部变量,表示对ArrayList修改次数的期望值,它的初始值为modCount
public Iterator<E> iterator() {
return listIterator();
}
public ListIterator<E> listIterator(final int index) {
checkForComodification();
rangeCheckForAdd(index);
final int offset = this.offset;
return new ListIterator<E>() {
int cursor = index;
int lastRet = -1;
//注意这里
int expectedModCount = ArrayList.this.modCount;
.......
}
....
}
.....
}
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
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];
}
}
正确写法:
方法1: 倒序循环,因为list删除只会导致当前元素之后的元素位置发生改变,所以采用倒序可以保证前面的元素没有变化。
/**
* 移除不符合的数据
* */
public static void screenData(List<Student> list1, List<Student> list2){
for(int i = list1.size() -1; i >= 0; i--){
for(int j = list2.size() -1; j >= 0; j--){
Student s1 = list1.get(i);
Student s2 = list2.get(j);
if(s1.getAge().equals(s2.getAge())){
list2.remove(s2);
}
}
}
}