Java容器的Iterator

446 阅读2分钟

迭代器Iterator

      迭代器(Iterator,也是一种设计模式)是一个对象,它的工作是遍历并选择序列中的对象,而客户端程序员不必知道或关心该序列底层的结构。此外,迭代器通常被称为轻量级对象:创建它的代价小。因此,经常可以见到对迭代器有些奇怪的限制;例如,Java的Iterator只能单向移动,这个Iterator只能用来:

  1. 使用方法iterator()要求容器返回一个Iterator,Iterator将准备好返回序列的第一个元素
  2. 使用next()获得序列中的下一个元素
  3. 使用hasNext()检查序列中是否还有元素
  4. 使用remove()将迭代器新近返回的元素删除
package p10;

import java.util.Iterator;
import java.util.List;

public class SimpleIteration {
    public static void main(String[] args) {
        List<Pet> pets = Pets.arrayList(12);
        Iterator<Pet> iterator = pets.iterator();
        while (iterator.hasNext()){
            Pet p = iterator.next();
            System.out.print(p.id() + ":" + p + " ");
        }
        System.out.println();
        for(Pet p:pets){
            System.out.print(p.id() + ":" + p + " ");
        }
        System.out.println();
        // An Iterator can also remove elements;
        iterator = pets.iterator();
        for(int i = 0;i < 6;i++){
            iterator.next();
            iterator.remove();
        }
        System.out.println(pets);
        /**
         * 0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx 8:Cymric 9:Rat 10:EgyptianMau 11:Hamster
         * 0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx 8:Cymric 9:Rat 10:EgyptianMau 11:Hamster
         * [Pug, Manx, Cymric, Rat, EgyptianMau, Hamster]
         */
    }
}

      如果你只是向前遍历List,并不打算修改List对象本身,那么你就可以看到forEach语法会显得更加简洁。

      Iterator还可以移除由next()产生的最后一个元素,这意味着在调用remove之前必须先调用next()。

      现在考虑创建一个display()方法,它不必知晓容器的确切类型。

package p10;

import java.util.*;

public class CrossContainerIteration {
    public static void display(Iterator<Pet> it){
        while (it.hasNext()){
            Pet p = it.next();
            System.out.print(p.id() + ":" + p + " ");
        }
        System.out.println();
    }
    public static void main(String[] args) {
        ArrayList<Pet> pets = Pets.arrayList(8);
        LinkedList<Pet> petsLL = new LinkedList<>(pets);
        HashSet<Pet> petsHS = new HashSet<>(pets);
        TreeSet<Pet> petsTS = new TreeSet<>(pets);
        display(pets.iterator());
        display(petsLL.iterator());
        display(petsHS.iterator());
        display(petsTS.iterator());
    }
}

Iterator源码

private class Itr implements Iterator<E> {
    int cursor;       // index of next element to return
    int lastRet = -1; // index of last element returned; -1 if no such
    int expectedModCount = modCount;

    Itr() {}

    public boolean hasNext() {
        return cursor != size; // 判断是否到底容器的最后
    }

    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size) // size 是容器的大小
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i]; // 返回next 并更新lastRet
    }

    public void remove() {
        if (lastRet < 0) // 如果remove之前没有调用next lastRet为-1 会抛异常
            throw new IllegalStateException();
        checkForComodification();

        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet; // 更新cursor,删除之后容器后面的元素会顶替上来
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }
}
ListIteration

      ListIterator是一个更加强大的Iterator的子类型,它只能适用于各类List类的访问。尽管Iterator只能向前移动,但是ListIterator可以双向移动。他还可以产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引,并且可以使用set()方法替换它访问过的最后一个元素。你可以通过调用listIterator方法产生一个指向List开始处的ListIterator,并且还可以通过调用listIterator(n)方法创建一个一开始就指向列表索引为n的元素处的ListIterator。

package p10;

import java.util.List;
import java.util.ListIterator;

public class ListIteration {
    public static void main(String[] args) {
        List<Pet> pets = Pets.arrayList(8);
        ListIterator<Pet> it = pets.listIterator();
        while (it.hasNext()){
            System.out.print(it.next() + ", " + it.nextIndex() +
                    ", " +it.previousIndex() + "; ");
        }
        System.out.println();
        // Backwards
        while (it.hasPrevious()){
            System.out.print(it.previous().id() + " ");
        }
        System.out.println();
        System.out.println(pets);
        it = pets.listIterator(3);
        while (it.hasNext()){
            it.next();
            it.set(Pets.randomPet());
        }
        System.out.println(pets);
        /**
         * Rat, 1, 0; Manx, 2, 1; Cymric, 3, 2; Mutt, 4, 3; Pug, 5, 4; Cymric, 6, 5; Pug, 7, 6; Manx, 8, 7;
         * 7 6 5 4 3 2 1 0
         * [Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug, Manx]
         * [Rat, Manx, Cymric, Cymric, Rat, EgyptianMau, Hamster, EgyptianMau]
         */
    }
}

ListIterator源码

private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) {
            super();
            cursor = index; // 可以传递参数该表cursor
        }

        public boolean hasPrevious() {
            return cursor != 0;
        }

        public int nextIndex() {
            return cursor;
        }

        public int previousIndex() {
            return cursor - 1;
        }

        @SuppressWarnings("unchecked")
        public E previous() {
            checkForComodification();
            int i = cursor - 1;
            if (i < 0)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i;
            return (E) elementData[lastRet = i];
        }

        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.set(lastRet, e); // 只有调用next方法的时候会更新lastRet,此时才能执行set方法,否则会报错
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }