孩子,当你出生的那天,java集合的森林中悄声回荡着你的名字:“Iterator”。
迭代器的书面解释
迭代器是一个对序列集合的高层次抽象,迭代器接口提供了一种方式去安全遍历和修改整个序列,在java中将其定义为Iterator。而Iterable接口定义了生成迭代器的方法,君临java整个序列类型集合类继承关系的最顶端。可见对序列进行安全遍历同时修改,是序列集合类的首要任务。
java的集合类主要包含两种类型,序列和哈希表。
序列指按一定顺序排列的对象组合,而哈希表则表示键值对映射。
先举个栗子
List<String> list = new ArrayList<>();
list.add("hello");
list.add(" ");
list.add("world");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
我们首先创建一个集合List,调用list.iterator()
方法生成一个迭代器,然后使用hasNext()
方法判断集合中是否还存在未遍历元素,使用next()
操作获取下一个元素。这就是迭代器的使用。我们分生成和使用两部分来分别说明。
Iterable 生成迭代器
Iterable接口的主要方法如下
public interface Iterable<T> {
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
其中,iterator()
方法负责生成一个迭代器,具体实现交给各自集合类。而forEach
方法为java1.8新增的默认方法,使用函数式编程遍历集合。
for each语法糖
要额外说一下这个语法,叫做 for each
for (T t : this) {
action.accept(t);
}
这是java提供的快速遍历集合的语法糖,经过javac编译后会使用迭代器进行遍历。例如上面的那个示例,如果开发过程中出现迭代器,IDEA会提示将迭代器优化为for (T t : 集合对象)
的形式。上文while()
代码经过优化后为
for (String s : list) {
System.out.println(s);
}
实际上经过编译,生成的class为
Iterator var2 = list.iterator();
while(var2.hasNext()) {
String s = (String)var2.next();
System.out.println(s);
}
至于为什么要在写法上使用语法糖代替迭代器,因为for each的写法代码量更少,更简洁,对开发人员更友好。
带学C语言老师:现代编程第一是给人看的,其次才是给电脑看的。
Iterator 迭代器
说完了迭代器的生成,下面来说迭代器本身。
public interface Iterator<E> {
/**
* 如果迭代器中包含更多的元素则返回true。
* 换句话说,next()方法将返回一个元素而不是抛出异常
*/
boolean hasNext();
/**
* 返回迭代器中的下一个元素
*/
E next();
/**
* 从底层集合中删除迭代器next方法返回的最后一个元素
* 每次调用next方法,之后只能调用一次remove方法
* 如果以该方法之外的方法修改底层集合,则不保证会出现什么问题
*
* 默认实现为抛出异常,每个集合自己实现安全的remove操作
*/
default void remove() {
throw new UnsupportedOperationException("remove");
}
}
迭代器的使用方法:
- 首先使用
hasNext()
方法判断迭代器中是否还有未遍历元素,如果返回true,则说明可以继续遍历;如果返回false,则说明迭代器遍历结束。 - 如果
hasNext()
方法返回true,则使用next()
方法返回迭代器的下个元素。 - 如果想移除集合中的某些数据,需要在调用
next()
方法后调用一次remove()
方法。