# 24. 如何使用 ListIterator 进行双向遍历?相比 Iterator 有哪些优势?

# 标准答案

ListIteratorIterator 的增强版,专门用于 List 结构,支持 双向遍历next()previous())、元素修改set())、插入和删除add()remove()),相比 Iterator 具有更强的操作能力。
它的优势包括:

  1. 支持双向遍历,可以使用 previous() 反向迭代 List,而 Iterator 只能前向遍历。
  2. 支持元素修改,可以在迭代过程中 set(E e) 修改当前元素,而 Iterator 只能删除,不能修改。
  3. 支持插入和删除add(E e) 可动态插入元素,而 Iterator 只能 remove() 删除元素。

# 答案解析

# 1. ListIterator 的基本使用

ListIterator 可以从 List任意索引位置 开始迭代:

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D"));
ListIterator<String> it = list.listIterator(); // 从索引 0 开始遍历

while (it.hasNext()) {
    System.out.print(it.next() + " "); // A B C D
}
1
2
3
4
5
6

反向遍历

while (it.hasPrevious()) {
    System.out.print(it.previous() + " "); // D C B A
}
1
2
3

可以看到,ListIterator 允许正向遍历后,反向回溯,这点是 Iterator 无法做到的。

# 2. ListIterator 相比 Iterator 的增强功能

功能 Iterator ListIterator
前向遍历 (next())
后向遍历 (previous())
删除元素 (remove())
修改元素 (set(E e))
添加元素 (add(E e))
获取当前索引 (nextIndex()/previousIndex())

可以看到,ListIteratorIterator 的超集,不仅能遍历,还能修改、插入、删除元素,更适合动态修改 List

# 3. ListIterator 插入、修改、删除元素

  • add(E e) 在当前位置插入元素
ListIterator<String> it = list.listIterator();
while (it.hasNext()) {
    String val = it.next();
    if (val.equals("B")) {
        it.add("X"); // 在 "B" 之后插入 "X"
    }
}
System.out.println(list); // [A, B, X, C, D]
1
2
3
4
5
6
7
8
  • set(E e) 修改当前元素
while (it.hasNext()) {
    if (it.next().equals("C")) {
        it.set("Y"); // 替换 C 为 Y
    }
}
System.out.println(list); // [A, B, X, Y, D]
1
2
3
4
5
6
  • remove() 删除当前元素
while (it.hasNext()) {
    if (it.next().equals("A")) {
        it.remove(); // 删除 A
    }
}
System.out.println(list); // [B, X, Y, D]
1
2
3
4
5
6

注意:

  1. 不能连续调用 remove(),必须 next()previous() 之后才能再次调用,否则会抛 IllegalStateException
  2. add(E e)set(E e) 不影响 remove() 的调用状态。

# 4. ListIterator 的常见错误

  • 错误1:遍历时使用 for-each 进行 add()remove()
for (String s : list) { // for-each 实际上是 Iterator 遍历
    if (s.equals("B")) {
        list.add("X"); // ConcurrentModificationException
    }
}
1
2
3
4
5
  • 正确方式:使用 ListIterator
ListIterator<String> it = list.listIterator();
while (it.hasNext()) {
    if (it.next().equals("B")) {
        it.add("X"); // 正确,避免 ConcurrentModificationException
    }
}
1
2
3
4
5
6
  • 错误2:连续调用 remove()
it.next();
it.remove();
it.remove(); // IllegalStateException
1
2
3
  • 正确方式
it.next();
it.remove();
it.next(); // 必须移动迭代器后才能再次调用 remove()
it.remove();
1
2
3
4

# 最佳实践

  1. 修改 List 结构时,使用 ListIterator,避免 ConcurrentModificationException
  2. 需要双向遍历 List 时,使用 ListIterator,比 Iterator 更灵活。
  3. 频繁插入、删除时,LinkedList.listIterator()ArrayList.listIterator() 更高效,因为 LinkedList 直接修改链表指针,而 ArrayList 删除元素需要数组移动。

# 深入追问

  • ArrayListLinkedListListIteratoradd()/remove() 时的性能有何区别?
  • ListIteratorset() 方法和 add() 方法的内部机制有何不同?
  • 为什么 ListIterator 不能在 for-each 结构中使用?

# 相关面试题

  • ListIterator 为什么比 Iterator 更灵活?
  • 为什么 ListIterator 不能用于 Set
  • ListIteratorLinkedListArrayList 中的性能表现?