集合学习总结2-List - --迭代器遍历的时候不能添加,会爆并发修改异常

本文探讨了List集合的特有遍历方式,包括正向遍历和倒序遍历,强调了ListIterator在遍历过程中可以使用add()方法添加元素而不会引发异常的特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

特有功能

 

List特有遍历方式1

List特有遍历方式2倒序.......前提条件,必须先正向遍历一遍,一般不使用.

但是这个ListIterator遍历过程中可以用他的add()方法,添加元素.不会爆异常.

<think>在Java中,使用迭代器遍历集合时直接修改集合结构(除了通过迭代器自身的remove方法)会抛出ConcurrentModificationException。要避免这个异常,同时又要遍历修改集合,有几种方法: 1. 使用迭代器自身的remove方法(只能删除,不能添加2. 使用并发集合类(如CopyOnWriteArrayList) 3. 遍历时收集需要修改元素遍历结束后再修改(适用于单线程) 4. 使用ListIterator(针对List,支持添加和删除) 下面分别给出示例:</think>### 如何安全使用迭代器遍历修改集合结构 在 Java 中,使用迭代器遍历修改集合结构会导致 `ConcurrentModificationException`。以下是四种安全解决方案,包含完整代码和解释: #### 方案 1:使用迭代器自身的修改方法(推荐) ```java List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C")); // 安全删除元素 Iterator<String> it = list.iterator(); while (it.hasNext()) { String item = it.next(); if ("B".equals(item)) { it.remove(); // 使用迭代器的 remove() 方法 } } System.out.println(list); // 输出: [A, C] // ListIterator 支持添加修改 ListIterator<String> listIt = list.listIterator(); while (listIt.hasNext()) { String item = listIt.next(); if ("A".equals(item)) { listIt.set("A+"); // 修改当前元素 listIt.add("New"); // 添加元素 } } System.out.println(list); // 输出: [A+, New, C] ``` **关键点**: - 使用 `iterator.remove()` 而非 `list.remove()` - `ListIterator` 额外提供 `add()` 和 `set()` 方法 - 仅适用于单线程环境 #### 方案 2:使用并发集合类(线程安全) ```java import java.util.concurrent.CopyOnWriteArrayList; CopyOnWriteArrayList<String> safeList = new CopyOnWriteArrayList<>( Arrays.asList("X", "Y", "Z") ); // 安全遍历修改(任意线程) safeList.forEach(item -> { if ("Y".equals(item)) { safeList.remove(item); // 直接操作集合 safeList.add(0, "NewY"); // 添加元素 } }); System.out.println(safeList); // 输出: [NewY, X, Z] ``` **原理**: - `CopyOnWriteArrayList` 在修改时创建新数组副本 - 迭代器始终使用原始数组快照 - 适合读多写少场景 #### 方案 3:使用显式锁控制(高并发) ```java import java.util.*; import java.util.concurrent.locks.ReentrantLock; List<String> sharedList = new ArrayList<>(Arrays.asList("Alpha", "Beta")); ReentrantLock lock = new ReentrantLock(); // 线程安全遍历修改 lock.lock(); try { Iterator<String> it = sharedList.iterator(); while (it.hasNext()) { String item = it.next(); if ("Beta".equals(item)) { it.remove(); sharedList.add("Gamma"); // 直接操作集合 } } } finally { lock.unlock(); } System.out.println(sharedList); // 输出: [Alpha, Gamma] ``` **适用场景**: - 写操作频繁的高并发环境 - 需确保整个操作序列的原子性 #### 方案 4:临时集合记录修改(无锁方案) ```java List<String> list = new ArrayList<>(Arrays.asList("One", "Two", "Three")); List<String> toAdd = new ArrayList<>(); List<String> toRemove = new ArrayList<>(); // 遍历时记录修改 for (String item : list) { if ("Two".equals(item)) { toRemove.add(item); toAdd.add("NewTwo"); } } // 批量应用修改 list.removeAll(toRemove); list.addAll(toAdd); System.out.println(list); // 输出: [One, NewTwo, Three] ``` **优点**: - 完全避免并发修改异常 - 适用于禁止加锁的复杂业务场景 ### 关键选择指南 | 场景 | 推荐方案 | 性能影响 | |--------------------------|------------------------|----------| | 单线程简单修改 | 迭代器自身方法 | 无 | | 读多写少的多线程环境 | `CopyOnWriteArrayList` | 写操作慢 | | 写频繁的高并发环境 | 显式锁控制 | 中等 | | 无法使用锁的复杂业务逻辑 | 临时集合记录 | 低 | **重要原则**: 1. 永远不要在遍历过程中直接调用集合的 `add()`/`remove()` 2. 多线程环境优先使用并发集合类 3. 批量修改优先使用临时集合方案
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值