> 文章列表 > 遍历的同时修改一个List有几种方式?

遍历的同时修改一个List有几种方式?

遍历的同时修改一个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());
}```

安陆市