java集合大家族之迭代器

    xiaoxiao2025-09-09  535

    引言

    任何容器,都必须有某种方式可以插入元素并将它们再次取回。对于List容器,add()是插入元素的方法之一,而get()是取出元素的方法之一。要使用容器,就必须对容器的确切类型编程,如果原本是对着List编码,但后来发现如果能够把形同的代码应用于Set,将会显得非常方便。

    Iterator

    迭代器Iterator(也是一种设计模式)的概念就可以用于达成此目的。迭代器是一个对象,它的工作是遍历并选择容器中的对象,而不必关心容器的类型是什么。此外,迭代器通常被称为轻量级对象:创建它的代价小。Java的Iterator只能单向移动。容器使用iterator()方法就可以返回一个Iterator,iterator将准备返回容器的一个元素。

    Iterator接口定义了如下几个方法:

    hasNext():检测容器中是否还有元素,如果有返回true。next():获取容器中的下一个元素。remove():移除由next()产生后的元素,所以remove必须在next()之后调用。remove是可选的方法,即不是所有的Iterator实现类都必须实现这个方法。 public static void display(Iterator<Integer> it) { while (it.hasNext()) { System.out.print(it.next()+" "); } System.out.println(); } public static void main(String[] args) { List<Integer> ll = Arrays.asList(78, 94, 54, 12, 5, 69, -8, 48, 48, 984, 14); LinkedList<Integer > link=new LinkedList<>(ll); HashSet<Integer> set = new HashSet<>(ll); TreeSet<Integer> tree = new TreeSet<>(ll); //打印 display(ll.iterator()); display(link.iterator()); display(set.iterator()); display(tree.iterator()); } /*Output: 78 94 54 12 5 69 -8 48 48 984 14 78 94 54 12 5 69 -8 48 48 984 14 48 5 69 54 -8 984 12 78 94 14 -8 5 12 14 48 54 69 78 94 984 */

    display()方法并不包含任何有关它遍历容器的类型信息,Iterator能够将遍历序列的操作与底层的解构分离,是将队列和消费队列的方法连接在一起耦合度最小的方式。正由于此,迭代器统一了对容器的访问方式。

    Iterable接口

    上面例子中的容器都是Collection类型的容器,可以说所有的Collection类型容器都可以使用迭代器,而非Collection类型的容器无法直接使用迭代器进行迭代。如Map,你只能把迭代器用于key序列或value序列。Collection类型的容器之所以都能使用迭代器的原因在于,Collection接口继承了Iterable接口,该接口包含了一个能够产生Iterator的iterator()方法:

    public interface Collection<E> extends Iterable<E> { public interface Iterable<T> { /** * Returns an {@link Iterator} for the elements in this object. * * @return An {@code Iterator} instance. */ Iterator<T> iterator(); }

    为了呈现迭代器的迭代原理,我们可以的实现一个简单的容器:

    public class MyCollection extends AbstractCollection<Integer> { private Integer[] arrays = {78, 59, -7, 15, 29, 10, 48, 2, 4}; @Override public Iterator<Integer> iterator() { return new Iterator<Integer>() { private int index = 0; @Override public boolean hasNext() { return index < arrays.length; } @Override public Integer next() { return arrays[index++]; } @Override public void remove() { throw new UnsupportedOperationException("remove"); } }; } @Override public int size() { return arrays.length; } public static void main(String[] args){ MyCollection myCollection=new MyCollection(); display(myCollection.iterator()); } public static void display(Iterator<Integer> it) { while (it.hasNext()) { System.out.print(it.next()+" "); } System.out.println(); } }

    输出: 78 59 -7 15 29 10 48 2 4

    如果我们要实现自己的容器类,我们不需要直接实现Collection接口,而是继承AbstractCollection类,因为AbstractCollection类它也是实现了Collection接口,不过它提供了Collection很多的默认实现,使得你可以创建AbstractCollection的子类型,而不必写过多的重复代码。我们可以看到如果你实现了Collection,就必须实现iterator()方法,就必须实现Iterator接口,而Iterator中定义的方法next()、hasNext()就需要我们自己去实现如何迭代元素。这就是为什么使用迭代器可以遍历Collection容器的原因。

    Iterable接口和foreach

    我们知道foreach语法主要用于数组,但是它也可以用于任何Collection对象。原因在于Iterable接口可以被foreach用来在序列中移动。如果你创建了任何Iterable的类,都可以将它用于foreach语句中:

    public class MyCollection extends AbstractCollection<Integer> { private Integer[] arrays = {78, 59, -7, 15, 29, 10, 48, 2, 4}; @Override public Iterator<Integer> iterator() { return new Iterator<Integer>() { private int index = 0; @Override public boolean hasNext() { return index < arrays.length; } @Override public Integer next() { return arrays[index++]; } @Override public void remove() { throw new UnsupportedOperationException("remove"); } }; } @Override public int size() { return arrays.length; } public static void main(String[] args) { MyCollection myCollection = new MyCollection(); for (Integer i : myCollection) { System.out.print(i+" "); } } }

    打印:78 59 -7 15 29 10 48 2 4

    注意:foreach语句可以用于数组或其他任何Iterable,但是数组并不是一个Iterable,这点是我们必须要注意的。

    ListIterator

    ListIterator是一个更强大的迭代器,它继承Iterator接口。它只能用于各种List类的访问,可以进行双向移动。你可以通过调用listIterator()方法产生一个指向List开始处的ListIterator,并且还可以通过调用listIterator(n)方法创建一个一开始就指向列表索引为n的元素处的ListIterator。下面是ListIterator新定义的方法:

    hasPrevious():检测容器是否还有前一个元素,如果有返回true。主要用于反向迭代和hasNext()正好相反。previous():获取容器的前一个元素。主要用于反向迭代和next()正好相反。nextIndex()和previousIndex():返回容器中前一个元素和后一个元素的索引。set(E):替换调用next或 previous方法后所指向的元素。必须在next或 previous方法之后调用。add(E):插入元素到容器中。 public static void display(Iterator<Integer> it) { while (it.hasNext()) { System.out.print(it.next()+" "); } System.out.println(); } public static void main(String[] args) { List<Integer> ll = Arrays.asList(78, 94, 54, 12, 5, 69, -8, 48, 48, 984, 14); ListIterator it=ll.listIterator(); //正向 while (it.hasNext()){ System.out.println(it.next()+", "+it.nextIndex()+", "+it.previousIndex()); } System.out.println(); //反向 while (it.hasPrevious()){ System.out.print(it.previous()+" "); } System.out.println(); //获取指向特定索引的迭代器 it=ll.listIterator(3); while (it.hasNext()){ it.next(); it.set(4); } System.out.println(ll); } /*Output: 78, 1, 0 94, 2, 1 54, 3, 2 12, 4, 3 5, 5, 4 69, 6, 5 -8, 7, 6 48, 8, 7 48, 9, 8 984, 10, 9 14, 11, 10 14 984 48 48 -8 69 5 12 54 94 78 [78, 94, 54, 4, 4, 4, 4, 4, 4, 4, 4] */
    转载请注明原文地址: https://ju.6miu.com/read-1302477.html
    最新回复(0)