由于上篇《ArrayList基本操作及高级用法》没有对ListIterator进行讲解,本文补上。
首先举个例子:
假设List遍历只有如下一种方式(以ArrayList为例):
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
假设Set遍历也只有下面这种方式(以HashSet为例):
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(3);
for (int i : set) {
System.out.println(i);
}
从下图可知,List和Set都是Collection的子类,如果List和Set的遍历方式是不同的(如上示例),那么开发者需要在遍历List和Set时分别了解它们的实现细节,从面向抽象的层面来说,这是不正确的,对开发者来说也是不友好的。
因此,Collection接口统一继承了Iterable接口,所有子类都必须实现该接口,那么所有的集合类都有了统一的遍历方式,对开发者来说也更加友好,也符合面向抽象的设计规范。
Iterator接口定义的方法如下:
public interface Iterator<E> {
/**
* 判断是否有下一个元素
*/
boolean hasNext();
/**
* 返回下一个元素
* 如果没有下一个元素,则抛出NoSuchElementException
*/
E next();
/**
* 移除迭代器next()返回的元素
*/
default void remove() {
throw new UnsupportedOperationException("remove");
}
/**
* 遍历迭代器中剩余的元素
*/
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
ListIterator是Iterator的子类,顾名思义,它是专门为List设计的迭代器,具有如下一些方法:
public interface ListIterator<E> extends Iterator<E> {
// Query Operations
/**
* 判断是否有下一个元素
*/
boolean hasNext();
/**
* 返回下一个元素
* 如果没有下一个元素,则抛出NoSuchElementException
*/
E next();
/**
* 判断是否有上一个元素
*/
boolean hasPrevious();
/**
* 返回上一个元素
* 如果没有上一个元素,则抛出NoSuchElementException
*/
E previous();
/**
* 下一个元素的索引
*/
int nextIndex();
/**
* 上一个元素的索引
*/
int previousIndex();
// 修改 操作
/**
* 移除迭代器next()返回的元素
*/
void remove();
/**
* 赋值
*/
void set(E e);
/**
* 添加元素
*/
void add(E e);
}
通过对比可知,hasPrevious()、previous()、nextIndex()、previousIndex()、set(E e)、add(E e)这几个方法是ListIterator独有的。
下面来对比一下两者的异同点:
相同点:都可以用来对List进行遍历。
不同点:
ListIterator | Iterator |
只能用来遍历List | 可以遍历所有集合类:List、Set、Queue |
可以向前和向后遍历 集合中存在的元素 | 只能向前遍历集合中的元素 |
可以使用nextIndex() 和 previousIndex() 方法,在遍历 List 时随时获取元素的索引。 | 无法使用 Iterator 获取索引 |
可以使用set(E e) 方法修改或替换元素 | 无法修改或替换集合中存在的元素 |
可以使用add(E e)方法将元素添加到集合中 | 无法添加元素 |