Java中的迭代器指南
1.绪论
迭代器是我们可以遍历一个集合的许多方法之一,就像每个选项一样,它有它的优点和缺点。
它是在Java 1.2中首次引入的,作为Enumerations和的替代物:
- 引入了改进的方法名称
- 使得从我们正在迭代的集合中移除元素成为可能。
- 并不保证迭代的顺序
在本教程中,我们将回顾一下简单的迭代器接口,学习如何使用它的不同方法。
我们还将检查更健壮的ListIterator扩展,它增加了一些有趣的功能。
2.迭代器接口
首先,我们需要从一个Collection中获得一个Iterator这是通过调用iterator()方法来实现的。
为了简单起见,我们将从一个列表中获得Iterator实例:
List<String> items = ...
Iterator<String> iter = items.iterator();
迭代器接口有三个核心的方法:
2.1. hasNext()
hasNext()方法可用于检查是否至少还有一个元素可供迭代。
它被设计为在while循环中作为一个条件使用:
while (iter.hasNext()) {
// ...
}
2.2. next()
next()方法可用于步入下一个元素,并获得它:
String next = iter.next();
在尝试调用next()之前,使用hasNext()是一个很好的做法。
迭代器对于集合并不保证以任何特定的顺序进行迭代,除非特定的实现提供了它。。
2.3. remove()
最后,如果我们想从集合中删除当前的元素,我们可以使用remove:。
iter.remove();
这是一种安全的方法,可以在遍历一个集合时删除元素,而不会有ConcurrentModificationException.的风险。
2.4.完整的迭代器例子
现在我们可以把它们结合起来,看看我们是如何把这三种方法结合起来用于集合过滤的:
while (iter.hasNext()) {
String next = iter.next();
System.out.println(next);
if( "TWO".equals(next)) {
iter.remove();
}
}
这就是我们通常使用迭代器的方式,我们提前检查是否有另一个元素,我们检索它,然后我们对它执行一些操作。
2.5.使用Lambda表达式进行迭代
正如我们在前面的例子中所看到的,当我们只想翻阅所有的元素并对其进行处理时,使用一个Iterator是非常冗长的。
从Java 8开始,我们有了forEachRemaining方法,它允许使用lambdas来处理剩余的元素:
iter.forEachRemaining(System.out::println);
3. ListIterator 接口
ListIterator是一个扩展,它为在列表上迭代增加了新的功能:
ListIterator<String> listIterator = items.listIterator(items.size());
请注意,我们可以提供一个起始位置,在本例中是List.的末端。
3.1.hasPrevious() 和 previous()
ListIterator可用于后向遍历,所以它提供了hasNext()和next()的等价物:
while(listIterator.hasPrevious()) {
String previous = listIterator.previous();
}
3.2. nextIndex() and previousIndex()
此外,我们可以遍历索引,而不是实际的元素:
String nextWithIndex = items.get(listIterator.nextIndex());
String previousWithIndex = items.get(listIterator.previousIndex());
如果我们需要知道我们当前正在修改的对象的索引,或者我们想保留一个被删除的元素的记录,这可能会被证明是非常有用的。
3.3. add()
add 方法,顾名思义,它允许我们在next()返回的项目之前和previous()返回的项目之后添加一个元素:
listIterator.add("FOUR");
3.4. set()
最后一个值得一提的方法是set(),它让我们替换在调用next()或previous()时返回的元素:
String next = listIterator.next();
if( "ONE".equals(next)) {
listIterator.set("SWAPPED");
}
重要的是要注意只有在之前没有调用add() 或remove() 时才能执行此操作。
3.5.完整的ListIterator例子
我们现在可以把它们全部结合起来,组成一个完整的例子:
ListIterator<String> listIterator = items.listIterator();
while(listIterator.hasNext()) {
String nextWithIndex = items.get(listIterator.nextIndex());
String next = listIterator.next();
if("REPLACE ME".equals(next)) {
listIterator.set("REPLACED");
}
}
listIterator.add("NEW");
while(listIterator.hasPrevious()) {
String previousWithIndex
= items.get(listIterator.previousIndex());
String previous = listIterator.previous();
System.out.println(previous);
}
在这个例子中,我们首先从List获得ListIterator,然后我们可以通过索引–获得下一个元素,这不会增加迭代器内部的当前元素–或者通过调用next获得。
然后我们可以用set替换一个特定的项目,用add.插入一个新的项目。
在达到迭代的终点后,我们可以向后修改更多的元素,或者干脆从下往上打印它们。
4.总结
Iterator接口允许我们在遍历一个集合时对其进行修改,这在简单的for/while语句中比较困难。这又给了我们一个很好的模式,我们可以在许多方法中使用,只需要对集合进行处理,同时保持良好的内聚性和低耦合性。
最后,像往常一样,完整的源代码可以在GitHub上找到。