# 24. 如何使用 ListIterator
进行双向遍历?相比 Iterator
有哪些优势?
# 标准答案
ListIterator
是 Iterator
的增强版,专门用于 List
结构,支持 双向遍历(next()
、previous()
)、元素修改(set()
)、插入和删除(add()
、remove()
),相比 Iterator
具有更强的操作能力。
它的优势包括:
- 支持双向遍历,可以使用
previous()
反向迭代List
,而Iterator
只能前向遍历。 - 支持元素修改,可以在迭代过程中
set(E e)
修改当前元素,而Iterator
只能删除,不能修改。 - 支持插入和删除,
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
2
3
4
5
6
反向遍历:
while (it.hasPrevious()) {
System.out.print(it.previous() + " "); // D C B A
}
1
2
3
2
3
可以看到,ListIterator
允许正向遍历后,反向回溯,这点是 Iterator
无法做到的。
# 2. ListIterator
相比 Iterator
的增强功能
功能 | Iterator | ListIterator |
---|---|---|
前向遍历 (next() ) | ✅ | ✅ |
后向遍历 (previous() ) | ❌ | ✅ |
删除元素 (remove() ) | ✅ | ✅ |
修改元素 (set(E e) ) | ❌ | ✅ |
添加元素 (add(E e) ) | ❌ | ✅ |
获取当前索引 (nextIndex()/previousIndex() ) | ❌ | ✅ |
可以看到,ListIterator
是 Iterator 的超集,不仅能遍历,还能修改、插入、删除元素,更适合动态修改 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
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
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
2
3
4
5
6
注意:
- 不能连续调用
remove()
,必须next()
或previous()
之后才能再次调用,否则会抛IllegalStateException
。 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
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
3
4
5
6
- 错误2:连续调用
remove()
it.next();
it.remove();
it.remove(); // IllegalStateException
1
2
3
2
3
- 正确方式
it.next();
it.remove();
it.next(); // 必须移动迭代器后才能再次调用 remove()
it.remove();
1
2
3
4
2
3
4
# 最佳实践
- 修改
List
结构时,使用ListIterator
,避免ConcurrentModificationException
。 - 需要双向遍历
List
时,使用ListIterator
,比Iterator
更灵活。 - 频繁插入、删除时,
LinkedList.listIterator()
比ArrayList.listIterator()
更高效,因为LinkedList
直接修改链表指针,而ArrayList
删除元素需要数组移动。
# 深入追问
ArrayList
和LinkedList
的ListIterator
在add()/remove()
时的性能有何区别?ListIterator
的set()
方法和add()
方法的内部机制有何不同?- 为什么
ListIterator
不能在for-each
结构中使用?
# 相关面试题
ListIterator
为什么比Iterator
更灵活?- 为什么
ListIterator
不能用于Set
? ListIterator
在LinkedList
和ArrayList
中的性能表现?