Java并发修改错误排查:遍历ArrayList匹配Player名称时遇异常
嘿,这个问题我之前踩过坑!你遇到的ConcurrentModificationError,大概率是因为在遍历ArrayList的同时修改了它的结构——哪怕是单线程环境下,只要用迭代器(包括for-each循环底层的迭代器)遍历的时候,调用了add()、remove()这类改变集合大小的方法,就会触发这个异常。首次输入正常可能是因为当时只是单纯遍历判断,没有修改集合;但修改文本框后,你的逻辑里可能不小心在遍历过程中对集合做了增删操作,或者Company类里的其他代码在同一流程中修改了这个ArrayList。
下面给你几个针对性的解决方案:
1. 用迭代器的remove()方法(如果需要删除匹配元素)
如果你遍历的目的是找到匹配name的Player并删除它,千万别直接调用list.remove(player),要用迭代器自带的remove()方法,它会同步更新迭代器和集合的状态:
// 假设Company类里有获取Player列表的方法getPlayerList() Iterator<Player> iterator = company.getPlayerList().iterator(); while (iterator.hasNext()) { Player currentPlayer = iterator.next(); if (currentPlayer.getName().equals(yourInputText)) { // 安全删除当前元素 iterator.remove(); // 这里可以加你的其他业务逻辑,比如提示找到匹配项 break; } }
2. 改用基于索引的普通for循环
如果不需要删除元素,或者想更灵活地操作集合,用普通的for循环(通过索引访问)可以避开迭代器的并发修改检测:
List<Player> playerList = company.getPlayerList(); for (int i = 0; i < playerList.size(); i++) { Player currentPlayer = playerList.get(i); if (currentPlayer.getName().equals(yourInputText)) { // 执行你的判断逻辑,比如标记找到匹配项 // 如果需要删除元素,记得调整索引: // playerList.remove(i); // i--; // 因为删除后后续元素会前移,避免跳过下一个元素 break; } }
3. 检查Company类中的集合操作逻辑
如果上面两种方法都没用,那要仔细看Company类里的代码:
- 是不是在遍历Player列表的同时,其他方法(比如更新Player信息的方法)修改了这个ArrayList的结构?
- 修改文本框后触发的事件中,有没有先对集合做了增删,再进行遍历?或者遍历过程中触发了集合的修改?
这种情况下,要把集合的修改操作和遍历操作分开执行,确保遍历的时候集合处于稳定状态。
4. 多线程场景下用线程安全集合
如果是UI线程和后台线程同时操作这个ArrayList(比如后台线程在更新Player列表,UI线程在遍历判断),那可以把ArrayList换成CopyOnWriteArrayList,它会在修改时创建集合的快照,遍历操作基于快照进行,不会触发并发修改异常:
// 在Company类里初始化集合时换成CopyOnWriteArrayList private List<Player> playerList = new CopyOnWriteArrayList<>();
先排查你的代码属于哪种情况,大概率是前两种场景导致的,调整遍历方式就能解决问题啦!
内容的提问来源于stack exchange,提问作者user9345978

