Java中的迭代器
Java Cursor 是一个 Iterator,用于逐个迭代或遍历或检索 Collection 或 Stream 对象的元素。 Java中有三个游标。
- 迭代器
- 枚举
- 列表迭代器
Note: SplitIterator can also be considered as a cursor as it is a type of Iterator only.
1. 迭代器
Java中的迭代器在 Collection 框架中用于一一检索元素。它是一个通用迭代器,因为我们可以将它应用于任何 Collection 对象。通过使用迭代器,我们可以执行读取和删除操作。它是 Enumeration 的改进版本,具有删除元素的附加功能。
每当我们要枚举所有 Collection 框架实现的接口(如 Set、List、Queue、Deque)和 Map 接口的所有实现类中的元素时,都必须使用迭代器。迭代器是整个集合框架唯一可用的游标。
可以通过调用 Collection 接口中的iterator()方法来创建迭代器对象。
句法:
Iterator itr = c.iterator();
Note: Here “c” is any Collection object. itr is of type Iterator interface and refers to “c”.
Java中迭代器接口的方法
Iterator 接口定义了三种方法,如下所示:
1. hasNext():如果迭代有更多元素,则返回true。
public boolean hasNext();
2. next():返回迭代中的下一个元素。如果没有更多元素,它会抛出NoSuchElementException 。
public Object next();
3. remove():删除迭代中的下一个元素。每次调用 next() 时只能调用一次此方法。
public void remove();
Note: remove() method can throw two exceptions namely as follows:
- UnsupportedOperationException : If the remove operation is not supported by this iterator
- IllegalStateException : If the next method has not yet been called, or the remove method has already been called after the last call to the next method.
Java迭代器如何在内部工作?
在本节中,我们将尝试了解Java迭代器及其方法在内部是如何工作的。让我们用下面的 LinkedList 对象来理解这个功能。
List cities = new LinkedList<>();
cities.add("G-1");
cities.add("G-2");
cities.add("G-3");
.
.
.
cities.add("G-n");
现在,让我们在 List 对象上创建一个 Iterator 对象,如下所示:
Iterator citiesIterator = cities.iterator();
“citiesIteartor”迭代器看起来像——
这里迭代器的光标指向列表的第一个元素之前。
现在,我们将运行以下代码片段。
citiesIterator.hasNext();
citiesIterator.next();
当我们运行上面的代码片段时,Iterator 的 Cursor 指向列表中的第一个元素,如上图所示。
现在,我们将运行以下代码片段。
citiesIterator.hasNext();
citiesIterator.next();
当我们运行上面的代码片段时,Iterator 的 Cursor 指向列表中的第二个元素,如上图所示。执行此过程以将迭代器的光标到达列表的末尾元素。
读取最后一个元素后,如果我们运行下面的代码片段,它会返回一个“false”值。
citiesIterator.hasNext();
由于 Iterator 的 Cursor 指向 List 的最后一个元素之后,hasNext() 方法返回一个 false 值。
Note: After observing all these diagrams, we can say that Java Iterator supports only Forward Direction Iteration as shown in the below diagram. So it is also known as Uni-Directional Cursor.
例子:
Java
// Java program to Demonstrate Iterator
// Importing ArrayList and Iterator classes
// from java.util package
import java.util.ArrayList;
import java.util.Iterator;
// Main class
public class Test {
// Main driver method
public static void main(String[] args)
{
// Creating an ArrayList class object
// Declaring object of integer type
ArrayList al = new ArrayList();
// Iterating over the List
for (int i = 0; i < 10; i++)
al.add(i);
// Printing the elements in the List
System.out.println(al);
// At the beginning itr(cursor) will point to
// index just before the first element in al
Iterator itr = al.iterator();
// Checking the next element where
// condition holds true till there is single element
// in the List using hasnext() method
while (itr.hasNext()) {
// Moving cursor to next element
int i = itr.next();
// Getting elements one by one
System.out.print(i + " ");
// Removing odd elements
if (i % 2 != 0)
itr.remove();
}
// Command for next line
System.out.println();
// Printing the elements inside the object
System.out.println(al);
}
}
Java
// Java program to demonstrate Enumeration
// Importing Enumeration and Vector classes
// from java.util package
import java.util.Enumeration;
import java.util.Vector;
// Main class
public class Test
{
// Main driver method
public static void main(String[] args)
{
// Creating a vector object
Vector v = new Vector();
// Iterating over vector object
for (int i = 0; i < 10; i++)
v.addElement(i);
// Printing elements in vector object
System.out.println(v);
// At beginning e(cursor) will point to
// index just before the first element in v
Enumeration e = v.elements();
// Checking the next element availability where
// condition holds true till there is a single element
// remaining in the List
while (e.hasMoreElements())
{
// Moving cursor to next element
int i = (Integer)e.nextElement();
// Print above elements in object
System.out.print(i + " ");
}
}
}
Java
// Java program to demonstrate ListIterator
// Importing ArrayList and List iterator classes
// from java.util package
import java.util.ArrayList;
import java.util.ListIterator;
// Main class
public class Test {
// Main driver method
public static void main(String[] args)
{
// Creating an object of ArrayList class
ArrayList al = new ArrayList();
// Iterating over Arraylist object
for (int i = 0; i < 10; i++)
// Adding elements to the Arraylist object
al.add(i);
// Print and display all elements inside object
// created above
System.out.println(al);
// At beginning ltr(cursor) will point to
// index just before the first element in al
ListIterator ltr = al.listIterator();
// Checking the next element availability
while (ltr.hasNext()) {
// Moving cursor to next element
int i = (Integer)ltr.next();
// Getting even elements one by one
System.out.print(i + " ");
// Changing even numbers to odd and
// adding modified number again in
// iterator
if (i % 2 == 0) {
// Change to odd
i++;
// Set method to change value
ltr.set(i);
// To add
ltr.add(i);
}
}
// Print and display statements
System.out.println();
System.out.println(al);
}
}
Java
// Java program to demonstrate iterators references
// Importing required classes from java.util package
import java.util.Enumeration;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Vector;
// Main class
public class GFG {
// Main driver method
public static void main(String[] args)
{
// Creating an object of Vector class
Vector v = new Vector();
// Creating three iterators
Enumeration e = v.elements();
Iterator itr = v.iterator();
ListIterator ltr = v.listIterator();
// Print class names of iterators
// using getClass() and getName() methods
System.out.println(e.getClass().getName());
System.out.println(itr.getClass().getName());
System.out.println(ltr.getClass().getName());
}
}
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0 1 2 3 4 5 6 7 8 9
[0, 2, 4, 6, 8]
拆分迭代器
与其他迭代器一样,拆分器用于遍历源的元素。源可以是 Collection、IO 通道或生成器函数。它包含在 JDK 8 中,用于支持除了顺序遍历之外的高效并行遍历(并行编程)。 Java Spliterator 接口是一个内部迭代器,可将流分成更小的部分。这些较小的零件可以并行处理。
Note: In real life programming, we may never need to use Spliterator directly. Under normal operations, it will behave exactly the same as Java Iterator.
Java迭代器的优点
- 我们可以将它用于任何 Collection 类。
- 它支持 READ 和 REMOVE 操作。
- 它是 Collection API 的通用游标。
- 方法名称简单易用。
另外,Iterator 也有一些限制,列举如下:
Java迭代器的局限性
- 在 CRUD 操作中,它不支持 CREATE 和 UPDATE 操作。
- 它仅支持作为单向迭代器的正向迭代。
- 与 Spliterator 相比,它不支持并行迭代元素,这意味着它仅支持顺序迭代。
- 与 Spliterator 相比,它不支持更好的性能来迭代大量数据。
2.枚举
它是一个用于获取遗留集合(Vector、Hashtable)元素的接口。枚举是 JDK 1.0 中出现的第一个迭代器,其余部分包含在 JDK 1.2 中,具有更多功能。枚举还用于指定SequenceInputStream的输入流。我们可以通过在任何向量对象上调用向量类的elements()方法来创建一个 Enumeration 对象
// Here "v" is an Vector class object. e is of
// type Enumeration interface and refers to "v"
Enumeration e = v.elements();
Enumeration 接口中有两种方法,即:
1. public boolean hasMoreElements():这个方法测试这个枚举是否包含更多的元素。
2. public Object nextElement():该方法返回本次枚举的下一个元素。如果没有更多元素,它会抛出 NoSuchElementException
Java
// Java program to demonstrate Enumeration
// Importing Enumeration and Vector classes
// from java.util package
import java.util.Enumeration;
import java.util.Vector;
// Main class
public class Test
{
// Main driver method
public static void main(String[] args)
{
// Creating a vector object
Vector v = new Vector();
// Iterating over vector object
for (int i = 0; i < 10; i++)
v.addElement(i);
// Printing elements in vector object
System.out.println(v);
// At beginning e(cursor) will point to
// index just before the first element in v
Enumeration e = v.elements();
// Checking the next element availability where
// condition holds true till there is a single element
// remaining in the List
while (e.hasMoreElements())
{
// Moving cursor to next element
int i = (Integer)e.nextElement();
// Print above elements in object
System.out.print(i + " ");
}
}
}
输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0 1 2 3 4 5 6 7 8 9
枚举存在一定的局限性,如下所示:
- 枚举仅适用于遗留类(向量、哈希表)。因此它不是一个通用迭代器。
- 无法使用枚举执行删除操作。
- 只有前向迭代是可能的。
Java枚举和迭代器的相似之处
- 两者都是Java游标。
- 两者都用于逐个迭代对象元素的集合。
- 两者都支持 READ 或 Retrieval 操作。
- 两者都是单向Java游标,这意味着仅支持正向迭代。
Java枚举和迭代器的区别
下表描述了Java枚举和迭代器之间的区别:
Enumeration Iterator Introduced in Java 1.0 Introduced in Java 1.2 Legacy Interface Not Legacy Interface It is used to iterate only Legacy Collection classes. We can use it for any Collection class. It supports only READ operation. It supports both READ and DELETE operations. It’s not Universal Cursor. It is a Universal Cursor. Lengthy Method names. Simple and easy-to-use method names.
3. 列表迭代器
仅适用于List集合实现类如ArrayList、LinkedList等,提供双向迭代。当我们要枚举 List 的元素时,必须使用 ListIterator。这个游标比迭代器有更多的功能(方法)。 ListIterator 对象可以通过调用 List 接口中的listIterator()方法来创建。
ListIterator ltr = l.listIterator();
Note: Here “l” is any List object, ltr is of type. ListIterator interface and refers to “l”. ListIterator interface extends the Iterator interface. So all three methods of Iterator interface are available for ListIterator. In addition, there are six more methods.
1.前进方向
1.1 hasNext():如果迭代有更多元素,则返回true
public boolean hasNext();
1.2 next():与Iterator的next()方法相同。返回迭代中的下一个元素。
public Object next();
1.3 nextIndex():如果列表迭代器位于列表末尾,则返回下一个元素索引或列表大小。
public int nextIndex();
2. 向后的方向
2.1 hasPrevious():如果迭代在向后遍历时有更多元素,则返回true。
public boolean hasPrevious();
2.2 previous():返回迭代中的前一个元素,如果没有更多元素存在,则可以抛出NoSuchElementException 。
public Object previous();
2.3 previousIndex():返回前一个元素的索引,如果列表迭代器位于列表的开头,则返回-1,
public int previousIndex();
3. 其他方法
3.1 remove():与Iterator的remove()方法相同。删除迭代中的下一个元素。
public void remove();
3.2 set(Object obj):将next()或previous()返回的最后一个元素替换为指定元素。
public void set(Object obj);
3.3 add(Object obj):将指定元素插入到列表中 next() 将返回的元素之前的位置
public void add(Object obj);
显然, ListIterator从 Iterator 继承的三个方法( hasNext() 、 next()和remove() )在两个接口中做的事情完全相同。 hasPrevious()和之前的操作与hasNext()和next()完全类似。前者操作指的是(隐式)光标之前的元素,而后者指的是光标之后的元素。上一个操作将光标向后移动,而下一个操作将光标向前移动。
ListIterator 没有当前元素;它的光标位置始终位于调用previous()将返回的元素与调用next() 将返回的元素之间。
1套() 方法可以抛出 4 个异常。
- UnsupportedOperationException:如果此列表迭代器不支持设置操作
- ClassCastException:如果指定元素的类阻止它被添加到此列表中
- IllegalArgumentException:如果指定元素的某些方面阻止它被添加到此列表中
- IllegalStateException:如果在最后一次调用 next 或 previous 之后既没有调用 next 也没有调用 previous,或者没有调用 remove 或 add
2. add()方法可以抛出 3 个异常。
- UnsupportedOperationException:如果此列表迭代器不支持 add 方法
- ClassCastException:如果指定元素的类阻止它被添加到此列表中
- IllegalArgumentException:如果此元素的某些方面阻止它被添加到此列表中
例子:
Java
// Java program to demonstrate ListIterator
// Importing ArrayList and List iterator classes
// from java.util package
import java.util.ArrayList;
import java.util.ListIterator;
// Main class
public class Test {
// Main driver method
public static void main(String[] args)
{
// Creating an object of ArrayList class
ArrayList al = new ArrayList();
// Iterating over Arraylist object
for (int i = 0; i < 10; i++)
// Adding elements to the Arraylist object
al.add(i);
// Print and display all elements inside object
// created above
System.out.println(al);
// At beginning ltr(cursor) will point to
// index just before the first element in al
ListIterator ltr = al.listIterator();
// Checking the next element availability
while (ltr.hasNext()) {
// Moving cursor to next element
int i = (Integer)ltr.next();
// Getting even elements one by one
System.out.print(i + " ");
// Changing even numbers to odd and
// adding modified number again in
// iterator
if (i % 2 == 0) {
// Change to odd
i++;
// Set method to change value
ltr.set(i);
// To add
ltr.add(i);
}
}
// Print and display statements
System.out.println();
System.out.println(al);
}
}
输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0 1 2 3 4 5 6 7 8 9
[1, 1, 1, 3, 3, 3, 5, 5, 5, 7, 7, 7, 9, 9, 9]
Note: Similarly, there are certain limitations with ListIterator. It is the most powerful iterator but it is only applicable for List implemented classes, so it is not a universal iterator.
要点
- 请注意,最初,任何迭代器引用都将指向集合中第一个元素的索引之前的索引。
- 我们不创建 Enumeration、Iterator、ListIterator 的对象,因为它们是接口。我们使用 elements()、iterator()、listIterator() 等方法来创建对象。这些方法有一个匿名的内部类,它扩展了各自的接口并返回这个类对象。
Note: The $ symbol in reference class name is a proof that concept of inner classes is used and these class objects are created.
这可以通过下面的代码来验证。有关内部类的更多信息,请参阅
Java
// Java program to demonstrate iterators references
// Importing required classes from java.util package
import java.util.Enumeration;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Vector;
// Main class
public class GFG {
// Main driver method
public static void main(String[] args)
{
// Creating an object of Vector class
Vector v = new Vector();
// Creating three iterators
Enumeration e = v.elements();
Iterator itr = v.iterator();
ListIterator ltr = v.listIterator();
// Print class names of iterators
// using getClass() and getName() methods
System.out.println(e.getClass().getName());
System.out.println(itr.getClass().getName());
System.out.println(ltr.getClass().getName());
}
}
java.util.Vector$1
java.util.Vector$Itr
java.util.Vector$ListItr