A Guide to Iterator in Java – Java中的迭代器指南

最后修改: 2018年 1月 10日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

An Iterator is one of many ways we can traverse a collection, and as every option, it has its pros and cons.

迭代器是我们可以遍历一个集合的许多方法之一,就像每个选项一样,它有其优点和缺点。

It was first introduced in Java 1.2 as a replacement of Enumerations and:

它是在Java 1.2中首次引入的,作为Enumerations和的替代。

In this tutorial, we’re going to review the simple Iterator interface to learn how we can use its different methods.

在本教程中,我们将回顾简单的迭代器接口,学习如何使用它的不同方法。

We’ll also check the more robust ListIterator extension which adds some interesting functionality.

我们还将检查更强大的ListIterator扩展,它增加了一些有趣的功能。

2. The Iterator Interface

2.迭代器接口

To start, we need to obtain an Iterator from a Collection; this is done by calling the iterator() method.

首先,我们需要从一个Collection中获得一个Iterator;这是通过调用iterator()方法来完成。

For simplicity, we’ll obtain Iterator instance from a list:

为了简单起见,我们将从一个列表中获得Iterator实例。

List<String> items = ...
Iterator<String> iter = items.iterator();

The Iterator interface has three core methods:

Iterator接口有三个核心方法。

2.1. hasNext()

2.1.hasNext()

The hasNext() method can be used for checking if there’s at least one element left to iterate over.

hasNext()方法可用于检查是否至少还有一个元素可以迭代。

It’s designed to be used as a condition in while loops:

它被设计为在while循环中作为一个条件使用。

while (iter.hasNext()) {
    // ...
}

2.2. next()

2.2.next()

The next() method can be used for stepping over the next element and obtaining it:

next()方法可用于步入下一个元素并获得它。

String next = iter.next();

It’s good practice to use hasNext() before attempting to call next().

在尝试调用next()之前,使用hasNext()是一个好的做法。

Iterators for Collections don’t guarantee iteration in any particular order unless particular implementation provides it.

迭代器集合不保证以任何特定的顺序迭代,除非特定的实现提供它。

2.3. remove()

2.3.remove()

Finally, if we want to remove the current element from the collection, we can use the remove:

最后,如果我们想从集合中删除当前元素,我们可以使用remove:

iter.remove();

This is a safe way to remove elements while iterating over a collection without a risk of a ConcurrentModificationException.

这是一种安全的方式,可以在遍历一个集合时删除元素,而不会有ConcurrentModificationException.的风险。

2.4. Full Iterator Example

2.4.完整的迭代器实例

Now we can combine them all and have a look at how we use the three methods together for collection filtering:

现在我们可以把它们结合起来,看看我们是如何把这三种方法一起用于集合过滤的。

while (iter.hasNext()) {
    String next = iter.next();
    System.out.println(next);
 
    if( "TWO".equals(next)) {
        iter.remove();				
    }
}

This is how we commonly use an Iterator, we check ahead of time if there is another element, we retrieve it and then we perform some action on it.

这就是我们通常使用迭代器的方式,我们提前检查是否有另一个元素,我们检索它,然后我们对它执行一些操作。

2.5. Iterating With Lambda Expressions

2.5.使用Lambda表达式进行迭代

As we saw in the previous examples, it’s very verbose to use an Iterator when we just want to go over all the elements and do something with them.

正如我们在前面的例子中所看到的,当我们只想翻阅所有的元素并对其进行处理时,使用一个Iterator是非常冗长的。

Since Java 8, we have the forEachRemaining method that allows the use of lambdas to processing remaining elements:

从Java 8开始,我们有了forEachRemaining方法,允许使用lambdas来处理剩余元素。

iter.forEachRemaining(System.out::println);

3. The ListIterator Interface

3.ListIterator接口

ListIterator is an extension that adds new functionality for iterating over lists:

ListIterator是一个扩展,它增加了在列表上迭代的新功能。

ListIterator<String> listIterator = items.listIterator(items.size());

Notice how we can provide a starting position which in this case is the end of the List.

注意我们如何提供一个起始位置,在本例中是List.的末端。

3.1. hasPrevious() and previous()

3.1.hasPrevious() previous()

ListIterator can be used for backward traversal so it provides equivalents of hasNext() and next():

ListIterator可用于后向遍历,因此它提供了hasNext()next()的等价物。

while(listIterator.hasPrevious()) {
    String previous = listIterator.previous();
}

3.2. nextIndex() and previousIndex()

3.2.nextIndex()previousIndex()

Additionally, we can traverse over indices and not actual elements:

此外,我们可以遍历索引而不是实际的元素。

String nextWithIndex = items.get(listIterator.nextIndex());
String previousWithIndex = items.get(listIterator.previousIndex());

This could prove very useful in case we need to know the indexes of the objects we’re currently modifying, or if we want to keep a record of removed elements.

如果我们需要知道我们当前正在修改的对象的索引,或者我们想保留一个被删除的元素的记录,这可能会证明非常有用。

3.3. add()

3.3.add()

The add method, which, as the name suggests, allows us to add an element before the item that would be returned by next() and after the one returned by previous():

add方法,顾名思义,允许我们在next()返回的项目之前和previous()返回的项目之后添加一个元素

listIterator.add("FOUR");

3.4. set()

3.4.set()

The last method worth mentioning is set(), which lets us replace the element that was returned in the call to next() or previous():

最后一个值得一提的方法是set(),它让我们替换调用next()previous()时返回的元素。

String next = listIterator.next();
if( "ONE".equals(next)) {
    listIterator.set("SWAPPED");
}

It’s important to note that this can only be executed if no prior calls to add() or remove() were made.

需要注意的是,只有在事先没有调用add()remove()的情况下才能执行。

3.5. Full ListIterator Example

3.5.完整的ListIterator实例

We can now combine them all to make a complete example:

我们现在可以把它们结合起来,组成一个完整的例子。

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);
}

In this example, we start by getting the ListIterator from the List, then we can obtain the next element either by index –which doesn’t increase the iterator’s internal current element – or by calling next.

在这个例子中,我们首先从List中获得ListIterator,然后我们可以通过索引–不增加迭代器内部的当前元素–或者通过调用next获得下一个元素。

Then we can replace a specific item with set and insert a new one with add.

然后我们可以用set替换一个特定的项目,用add.插入一个新项目。

After reaching the end of the iteration, we can go backward to modify additional elements or simply print them from bottom to top.

在达到迭代的终点后,我们可以向后修改更多的元素,或者干脆从下往上打印它们。

4. Conclusion

4.结论

The Iterator interface allows us to modify a collection while traversing it, which is more difficult with a simple for/while statement. This, in turn, gives us a good pattern we can use in many methods that only requires collections processing while maintaining good cohesion and low coupling.

Iterator接口允许我们在遍历一个集合时对其进行修改,这在简单的for/while语句中比较困难。这又给了我们一个很好的模式,我们可以在许多方法中使用,只需要对集合进行处理,同时保持良好的内聚性和低耦合性。

Finally, as always the full source code is available over at GitHub.

最后,像往常一样,完整的源代码可在GitHub上获得。