Skip to content

ListIterator:List 的双向迭代器

ListIterator vs Iterator

Iterator 只能向前走,ListIterator 可以向前也可以向后:

能力IteratorListIterator
向前遍历
向后遍历
修改元素
添加元素
获取当前位置

获取方式也不同:

java
// Iterator:所有 Collection 都有
Iterator<E> it = collection.iterator();

// ListIterator:只有 List 有
ListIterator<E> it = list.listIterator();

双向遍历

ListIterator 有一个「隐式游标」在元素之间:

元素:    [A]    [B]    [C]    [D]
游标位置:  ^     ^     ^     ^     ^
          |     |     |     |     |
索引位置: 0     1     2     3     4

基础双向遍历

java
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));

ListIterator<String> it = list.listIterator();

// 正向:从游标位置向后走
while (it.hasNext()) {
    int idx = it.nextIndex();
    String val = it.next();
    System.out.println("索引 " + idx + ": " + val);
}

// 此时游标在末尾(-1 之后)

// 反向:从游标位置向前走
while (it.hasPrevious()) {
    int idx = it.previousIndex();
    String val = it.previous();
    System.out.println("索引 " + idx + ": " + val);
}

修改元素:set()

set() 修改上一个 next()previous() 返回的元素:

java
List<String> list = new ArrayList<>(Arrays.asList("A", "b", "C"));

ListIterator<String> it = list.listIterator();

while (it.hasNext()) {
    String val = it.next();
    // 将小写字母转为大写
    if (val.equals(val.toLowerCase())) {
        it.set(val.toUpperCase()); // 修改当前元素
    }
}
System.out.println(list); // [A, B, C]

添加元素:add()

add() 在游标前面插入新元素,然后游标移到新元素之后:

java
List<String> list = new ArrayList<>(Arrays.asList("A", "C"));

ListIterator<String> it = list.listIterator();

// 移动到 "A" 之后
it.next();

// 在 "A" 和 "C" 之间插入 "B"
it.add("B");

System.out.println(list); // [A, B, C]

有序插入:利用游标特性

ListIterator 的游标特性让它非常适合有序插入:

java
// 在有序 List 中插入元素,保持有序
public static <T extends Comparable<T>> void insertSorted(List<T> list, T item) {
    ListIterator<T> it = list.listIterator();

    while (it.hasNext()) {
        T current = it.next();
        // 如果当前元素比要插入的大,就退回去
        if (current.compareTo(item) > 0) {
            it.previous();
            break;
        }
    }
    it.add(item); // 在正确位置插入
}

// 测试
List<Integer> sorted = new ArrayList<>(Arrays.asList(1, 3, 5, 7));
insertSorted(sorted, 4);
System.out.println(sorted); // [1, 3, 4, 5, 7]

替换所有匹配元素

java
// 用 ListIterator 实现 replaceAll
public static <T> void replaceAll(List<T> list, T oldVal, T newVal) {
    ListIterator<T> it = list.listIterator();
    while (it.hasNext()) {
        if (Objects.equals(oldVal, it.next())) {
            it.set(newVal);
        }
    }
}

List<String> list = new ArrayList<>(Arrays.asList("a", "b", "a", "c"));
replaceAll(list, "a", "X");
System.out.println(list); // [X, b, X, c]

游标位置控制

java
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));

ListIterator<String> it = list.listIterator();

// 从指定索引开始:从索引 2 开始(C)
it = list.listIterator(2);
System.out.println("从索引 2 开始: " + it.next()); // C

// 在任意位置插入
it = list.listIterator(2); // 回到索引 2
it.add("X");               // 在 C 前面插入 X
System.out.println(list);   // [A, B, X, C, D, E]

总结

要点说明
获取方式list.listIterator()list.listIterator(index)
向前hasNext() + next()
向后hasPrevious() + previous()
修改set(element) ——修改上一个遍历返回的元素
添加add(element) ——在游标前插入
删除remove() ——删除上一个遍历返回的元素
适用仅限 List,Set/Map 不支持

一句话:ListIterator 是 Iterator 的「升级版」——双向移动、随意修改,是 List 遍历的瑞士军刀。


相关链接

基于 VitePress 构建