Java11遍历列表时添加元素报ConcurrentModificationException有哪些解决方法?
异常触发原因
你遇到的ConcurrentModificationException,核心原因是在使用forEach遍历ArrayList时直接修改了列表的结构(新增/删除元素)。Java的ArrayList采用fail-fast设计,迭代过程中会校验列表的修改次数,一旦检测到结构变化就会直接抛出该异常。
除此之外你的代码还有三个隐藏问题:
- 两个
Person实例共享了同一个hobbies列表,修改任意一个的爱好会同步影响另一个,不符合常规业务逻辑 Collections.singletonList返回的是不可变列表,后续如果尝试修改这个列表会直接抛出UnsupportedOperationExceptionhobby.getMyHobby().toLowerCase()没有生效:String是不可变类,需要调用setMyHobby把转换后的小写值赋值回去
可行解决办法
- 方案1:遍历过程中先收集待新增的元素,遍历结束后统一添加
这是最常用的无额外依赖的方案,不会触发fail-fast校验,性能损耗极小,适配绝大多数业务场景 - 方案2:使用普通for下标循环遍历爱好列表
下标遍历不依赖迭代器,修改列表结构不会触发异常,但要注意新增元素时的下标越界问题 - 方案3:将存储爱好的
ArrayList替换为java.util.concurrent.CopyOnWriteArrayList
该并发容器专门为频繁遍历、少量修改的场景设计,遍历过程中修改结构不会抛出异常,但修改时会复制整个列表,内存开销稍高
修正代码示例(采用方案1实现)
import lombok.Data; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; public class Test { public static void main(String[] args) throws IOException { List<Person> myList = new ArrayList<>(); // 给每个Person单独初始化hobbies列表,避免共享 List<Hobby> hobbies1 = new ArrayList<>(); hobbies1.add(new Hobby("SKI")); hobbies1.add(new Hobby("reading")); Person p = new Person("R", hobbies1); List<Hobby> hobbies2 = new ArrayList<>(); hobbies2.add(new Hobby("SKI")); hobbies2.add(new Hobby("reading")); Person p1 = new Person("M", hobbies2); myList.add(p); myList.add(p1); myList.forEach(currentElement -> { if (Objects.isNull(currentElement.getHobbies())) { // 如果后续需要修改爱好列表,不要直接用singletonList,套一层ArrayList保证可修改 currentElement.setHobbies(new ArrayList<>(Collections.singletonList(new Hobby("NOTHING")))); } else { List<Hobby> toAdd = new ArrayList<>(); currentElement.getHobbies().forEach(hobby -> { if (hobby.getMyHobby().equals("SKI")) { // 先收集待新增的爱好,不直接修改遍历中的原列表 toAdd.add(new Hobby("SAILING")); } else { // 字符串不可变,需要赋值回去修改才会生效 hobby.setMyHobby(hobby.getMyHobby().toLowerCase()); } }); // 遍历结束后统一添加所有待新增元素 currentElement.getHobbies().addAll(toAdd); } }); } @Data static class Person { String name; List<Hobby> hobbies; public Person(String name, List<Hobby> hobbies) { this.name = name; this.hobbies = hobbies; } } @Data static class Hobby { String myHobby; public Hobby(String myHobby) { this.myHobby = myHobby; } } }
内容的提问来源于stack exchange,提问作者freecoderw
相关产品推荐
相关产品推荐

