Java 迭代器

Java 迭代器

Java游标是一个迭代器,用于逐一迭代、遍历或检索一个集合或流对象的元素。 在Java中有三种游标

  1. 迭代器
  2. 枚举
  3. ListIterator

注意: SplitIterator也可以被认为是游标,因为它只是Iterator的一种类型。

Java中的迭代器

1.迭代器

Java中的迭代器在Collection框架中被用来一个一个地检索元素。它是一个 通用的 迭代器,因为我们可以将它应用于任何集合对象。通过使用Iterator,我们可以执行读取和删除操作。它是Enumeration的改进版,具有删除元素的额外功能。

当我们想枚举所有Collection框架实现的接口中的元素时,必须使用Iterator,比如Set, List, Queue, Deque,以及所有Map接口的实现类。迭代器是整个集合框架中 唯一 可用的游标。
迭代器对象可以通过调用Collection接口中的iterator()方法创建。

语法

Iterator itr = c. **iterator** ();

注: 这里 “c “是任何集合对象。 itr是Iterator接口类型,指的是 “c”。

Java中迭代器接口的方法

迭代器接口定义了 三个 方法,如下所示。

1. hasNext(): 如果迭代有更多的元素,返回真。

public boolean hasNext();

2. next(): 返回迭代中的下一个元素。如果没有更多的元素存在,它会抛出 NoSuchElementException

public Object next();

3.remove(): 删除迭代中的下一个元素。这个方法在每次调用next()时只能被调用一次。

public void remove();

注意: remove()方法可以抛出两种异常,即如下所示。

  • UnsupportedOperationException : 如果该迭代器不支持删除操作。
  • IllegalStateException : 如果下一个方法还没有被调用,或者在最后一次调用下一个方法后,删除方法已经被调用。

Java迭代器是如何在内部工作的

在本节中,我们将尝试了解Java Iterator和它的方法是如何在内部工作的。让我们以下面的LinkedList对象来理解这一功能。

List<String> cities = new LinkedList<>(); 
cities.add("G-1"); 
cities.add("G-2"); 
cities.add("G-3"); 
. 
. 
. 
cities.add("G-n");

现在,让我们在List对象上创建一个Iterator对象,如下所示。

Iterator<String> citiesIterator = cities.iterator();

citiesIteartor “的迭代器将看起来像 —

Java中的迭代器

这里迭代器的光标指向列表的第一个元素之前。

现在,我们将运行以下代码片段。

citiesIterator.hasNext();
citiesIterator.next();

Java中的迭代器

当我们运行上述代码片断时,Iterator的Cursor指向列表中的第一个元素,如上图所示。

现在,我们将运行下面的代码片断。

citiesIterator.hasNext();
citiesIterator.next();

Java中的迭代器

当我们运行上面的代码片段时,Iterator的Cursor指向列表中的第二个元素,如上图所示。按照这个过程,Iterator的Cursor就会到达List的最后一个元素。

Java中的迭代器

在读完最后一个元素后,如果我们运行下面的代码片断,它会返回一个 “false “值。

citiesIterator.hasNext();

Java中的迭代器

由于Iterator的Cursor指向List的最后一个元素之后,hasNext()方法返回一个假值。

注意: 在观察了所有这些图之后,我们可以说Java Iterator只支持正向迭代,如下图所示。所以它也被称为单向游标。

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<Integer> al = new ArrayList<Integer>();
 
        // 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<Integer> 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);
    }
}

输出

[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]

分割器(SplitIterator)

拆分器,像其他迭代器一样,用于遍历一个源的元素。一个源可以是一个集合,一个IO通道,或者一个生成器函数。它包含在JDK 8中,除了顺序遍历之外,还支持高效的并行遍历(并行编程)。Java Spliterator接口是一个内部迭代器,它将流分成更小的部分。这些小部分可以被并行处理。

注意: 在现实的编程中,我们可能永远不需要直接使用Spliterator。在正常操作下,它的行为与Java Iterator完全一样。

Java Iterator的优点

  • 我们可以对任何集合类使用它。
  • 它同时支持READ和REMOVE操作。
  • 它是一个用于集合API的通用游标。
  • 方法名称简单,易于使用。

此外,Iterator还有一些限制,如下所示。

Java Iterator的局限性

  • 在CRUD操作中,它不支持CREATE和UPDATE操作。
  • 它只支持正向迭代,是一个单向的迭代器。
  • 与Spliterator相比,它不支持并行迭代元素,这意味着它只支持顺序迭代。
  • 与Spliterator相比,它不支持更好的性能来迭代大量的数据。

2.枚举

它是一个用于获取传统集合(Vector, Hashtable)元素的接口。枚举是JDK 1.0中出现的第一个迭代器,在JDK 1.2中又加入了更多的功能。Enumerations也被用来指定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 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 

枚举有一定的限制,具体如下。

  • 枚举只适用于 传统的 类(Vector, Hashtable)。因此,它不是一个通用的迭代器。
  • 删除操作不能用枚举来执行。
  • 只有正向的迭代是可能的。

Java枚举和迭代器的相似之处

  • 两者都是Java游标。
  • 两者都用于逐一迭代对象元素的集合。
  • 都支持READ或Retrieval操作。
  • 两者都是单向的Java游标,即只支持正向的迭代。

Java枚举和迭代器之间的区别

下表描述了Java Enumeration和Iterator之间的区别。

枚举 迭代器
引入于Java 1.0 在Java 1.2中引入
遗留接口 非遗留接口
它只用于迭代遗留的集合类。 我们可以对任何集合类使用它。
它只支持READ操作。 它同时支持READ和DELETE操作。
它不是通用游标。 它是一个通用游标。
冗长的方法名。 简单和易于使用的方法名称。

3.ListIterator

它只适用于List集合的实现类,如ArrayList, LinkedList等。它提供了双向的迭代。当我们想枚举List的元素时,必须使用ListIterator。这个游标比迭代器有更多的功能(方法)。ListIterator对象可以通过调用List接口中的listIterator()方法创建。

ListIterator ltr = l. **listIterator** ();

注意: 这里 “l “是任何List对象,ltr是类型。ListIterator接口,指的是 “l”。ListIterator接口扩展了Iterator接口。所以Iterator接口的所有三个方法都对ListIterator可用。此外,还有 六个 方法。

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() 和previous操作与hasNext()和next()是完全相似的 。 前一个操作指的是(隐式)光标之前的元素,而后者指的是光标之后的元素。前一个操作将光标向后移动,而后一个操作则将其向前移动。

ListIterator没有当前元素;它的光标位置总是位于调用 previous()返回的元素和调用Next()返回的元素之间。

1.set()方法可以抛出4个异常。

  • UnsupportedOperationException:如果该列表迭代器不支持set操作
  • ClassCastException:如果指定元素的类别使其不能被添加到这个列表中
  • IllegalArgumentException:如果指定元素的某些方面阻止它被添加到这个列表中。
  • IllegalStateException:如果没有调用next和previous,或者在最后一次调用next或previous之后调用了remove或add。

2. add()方法可以抛出3个异常。

  • UnsupportedOperationException:如果这个列表迭代器不支持add方法。
  • ClassCastException:如果指定元素的类别使其不能被添加到这个列表中。
  • IllegalArgumentException:如果这个元素的某些方面阻止它被添加到这个列表中。

例子

// 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]

注意: 同样地,ListIterator也有一定的局限性 。 它是最强大的迭代器,但它只适用于List实现的类,所以它不是一个通用的迭代器。

重要提示

  1. 请注意,最初,任何迭代器的引用都会指向集合中第一个元素的索引之前的那个索引。
  2. 我们不创建 Enumeration, Iterator, ListIterator 的对象,因为它们是接口。我们使用 elements(), iterator(), listIterator() 等方法来创建对象。这些方法有一个匿名的内部类,它扩展了各自的接口,并返回这个类的对象。

注意: 参考类名称中的 $ 符号证明了内类的概念被使用,这些类对象被创建。

这可以通过下面的代码进行验证。更多关于内部类的信息请参考

// 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.Vector1
java.util.VectorItr
java.util.Vector$ListItr

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程