ListIterator的add()在游标前插入元素并使游标后移,set()则替换上一次next()/previous()返回的元素;二者不可混用,add后不能立即set,需严格遵循游标状态。
listiterator 提供了在遍历 list 时安全地修改集合的能力,其中 add() 和 set() 是两个关键方法,它们作用于“当前游标位置”,但行为有本质区别:前者插入新元素并使游标后移一位,后者替换上一次调用 next() 或 previous() 返回的元素。正确理解游标状态是实战成功的核心。
add():在游标前插入,不干扰后续遍历逻辑
add(E e) 总是在当前游标所在位置**之前**插入新元素。插入后,游标会自动向后移动一位(即指向新插入元素的后方),因此下一次调用 next() 将跳过新元素,而 previous() 则可立即访问它。
- 必须在调用
next()或previous()后才能安全调用add()(否则可能抛IllegalStateException) - 插入不影响已遍历过的元素,也不会导致
ConcurrentModificationException - 示例:遍历时对所有偶数前插入标记字符串
set():仅能替换上一次 next()/previous() 返回的元素
set(E e) 不改变集合结构,只修改上一次由 next() 或 previous() 取出的元素值。它要求必须已调用过取值操作,且之后未执行 add() 或 remove() —— 否则抛异常。
- 不能用于首次迭代(没取过值),也不能在
add()后立刻调用 - 常用于“就地更新”场景,如统一转大写、打日志标记等
- 注意:若想替换当前索引处的元素但尚未调用
next(),需先调用一次再set()
add() 与 set() 混合使用的典型陷阱与对策
两者不可随意交替使用。例如,在 next() 后调用 set() 是合法的;但若在 next() 后先 add(),再试图 set(),就会失败——因为 add() 使“最近返回元素”的状态失效。
- 策略一:需要插入+更新,分两步走:先
add()新元素,再用新游标位置next()+set() - 策略二:明确区分意图——插入用
add(),修正用set(),避免交叉调用 - 调试技巧:打印
iter.nextIndex()辅助判断当前游标位置
替代方案提醒:普通 for 循环不适用动态修改
直接用 for (int i = 0; i 遍历时调用 <code>list.add(i, x) 或 list.set(i, x) 虽语法合法,但极易因索引偏移导致漏处理或重复处理。例如在 i=1 处插入,原 i=1 元素变成 i=2,而循环仍会递增到 i=2,跳过它。ListIterator 的游标机制正是为规避这类问题而设计。

















