遍历的同时修改一个List有几种方式?
遍历的同时修改一个List有几种方式?
- 遍历的同时修改一个List有几种方式?
-
- 1. 通过普通的for循环
- 2. 使用迭代器循环
- 3. 将原来的copy一份副本,遍历原来的list,然后删除副本(fail-safe)
- 4. 使用并发安全的集合类
- 5. 通过Stream的过滤方法,因为Stream每次处理后都会生成一个新的Stream,不存在并发问题,所以Stream的filter也可以修改list集合
遍历的同时修改一个List有几种方式?
我们知道,在foreach的同时修改集合,会触发fail-fast机制,要避免fail-fast机制,有如下处理方案:
1. 通过普通的for循环
由于在循环中删除元素后,list的索引会自动变化,list.size()获取到的list长度也会实时更新,所以会造成漏掉被删除元素后一个索引的元素。
比如循环到第2个元素时你把它删了,接下来去访问第3个元素,实际上访问到的是原来list的第4个元素,因为原来的第3个元素变成了现在的第2个元素。这样就造成了元素的遗漏。
public void listRemove() { List<Student> students = this.getStudents(); for (int i=0; i<students.size(); i++) { if (students.get(i).getId()%3 == 0) { Student student = students.get(i); students.remove(student); } }
}
2. 使用迭代器循环
public void iteratorRemove() { List<Student> students = this.getStudents(); Iterator<Student> stuIter = students.iterator(); while (stuIter.hasNext()) { Student student = stuIter.next(); if (student.getId() % 2 == 0) {//这里要使用Iterator的remove方法移除当前对象,如果使用List的remove方法,则同样会出现ConcurrentModificationException stuIter.remove();} }
}
3. 将原来的copy一份副本,遍历原来的list,然后删除副本(fail-safe)
public void copyRemove() {// 注意,这种方法的equals需要重写List<Student> students = this.getStudents();List<Student> studentsCopy = deepclone(students);for(Student stu : students) {if(needDel(stu)) {studentsCopy.remove(stu);}}
}
4. 使用并发安全的集合类
public void cowRemove() { List<String> students = new CopyOnWriteArrayList<>(this.getStudents());for(Student stu : students) {if(needDel(stu)) {studentsCopy.remove(stu);}}
}
5. 通过Stream的过滤方法,因为Stream每次处理后都会生成一个新的Stream,不存在并发问题,所以Stream的filter也可以修改list集合
public List<String> streamRemove() { List<String> students = this.getStudents();return students.stream().filter(this::needDel).collect(Collectors.toList());
}```