Java 集合:迭代器(Iterator, Iterable)

Iterator接口

public interface Iterator<E> {

    boolean hasNext();

    E next();

    void remove();
}

访问元素前需要使用hasNext进行判断是否有元素存在,如果有再通过next操作获取,直接使用next操作而不进行hasNext检测,当到达末尾时会抛出NoSuchElement异常

Iterator的remove操作

好久没有看JDK代码了,今天翻看Java Core看到迭代器里面的注意点,居然一点都回忆不起来了。先看如下代码:

        Iterator<String> iter = list.iterator();
        String s = iter.next();
        iter.remove();

那么这里iter.remove()删除的是哪个元素,删除的是列表中的第一个元素,通用一点来讲是迭代器上一次next()所返回的那个元素。又有如下代码:

        Iterator<String> iter = list.iterator();
        String s = iter.next();
        iter.remove();
        iter.remove();

如果去实际运行的话会报:java.lang.IllegalStateException异常即,每次remove都应该有对应的一次next,其实就是两两配对的,remove的就是next返回的那个元素。

从AbstractList的源码中可以看到Iterator的一个基本实现:

 1 private class Itr implements Iterator<E> {
 2         /**
 3          * Index of element to be returned by subsequent call to next.
 4          */
 5         int cursor = 0;
 6 
 7         /**
 8          * Index of element returned by most recent call to next or
 9          * previous.  Reset to -1 if this element is deleted by a call
10          * to remove.
11          */
12         int lastRet = -1;
13 
14         /**
15          * The modCount value that the iterator believes that the backing
16          * List should have.  If this expectation is violated, the iterator
17          * has detected concurrent modification.
18          */
19         int expectedModCount = modCount;
20 
21         public boolean hasNext() {
22             return cursor != size();
23         }
24 
25         public E next() {
26             checkForComodification();
27             try {
28                 int i = cursor;
29                 E next = get(i);
30                 lastRet = i;
31                 cursor = i + 1;
32                 return next;
33             } catch (IndexOutOfBoundsException e) {
34                 checkForComodification();
35                 throw new NoSuchElementException();
36             }
37         }
38 
39         public void remove() {
40             if (lastRet < 0)
41                 throw new IllegalStateException();
42             checkForComodification();
43 
44             try {
45                 AbstractList.this.remove(lastRet);
46                 if (lastRet < cursor)
47                     cursor--;
48                 lastRet = -1;
49                 expectedModCount = modCount;
50             } catch (IndexOutOfBoundsException e) {
51                 throw new ConcurrentModificationException();
52             }
53         }
54 
55         final void checkForComodification() {
56             if (modCount != expectedModCount)
57                 throw new ConcurrentModificationException();
58         }
59     }

可以看到有lastRet和cursor两个变量,前者用于代表next()操作返回的元素的索引,后者用于表示下一次next()调用是应该返回的元素的索引值。每当一次remove操作后lastRet就被清空了,同时cursor--,因为lastRet对应的元素在cursor前面,而此时其被remove了,那么cursor的值必然要减一。其实这里的迭代器实现都基本上被AbstractList的子类覆盖了,如LinkedList,ArrayList。前者不支持随机访问肯定不能用索引值作为获取元素的实现,否则迭代器效率就太低了。

ListIterator(extends Iterator<E>)

List接口除了继承Iterable接口外,还有几个额外的方法(listIterator)用来获取专门针对List的迭代器(即ListIterator)可以看一下LinkedList的迭代器实现:

private class ListItr implements ListIterator<E> {
        private Node<E> lastReturned = null;
        private Node<E> next;
        private int nextIndex;
        private int expectedModCount = modCount;

        ListItr(int index) {
            // assert isPositionIndex(index);
            next = (index == size) ? null : node(index);
            nextIndex = index;
        }

        public boolean hasNext() {
            return nextIndex < size;
        }

        public E next() {
            checkForComodification();
            if (!hasNext())
                throw new NoSuchElementException();

            lastReturned = next;
            next = next.next;
            nextIndex++;
            return lastReturned.item;
        }

        public boolean hasPrevious() {
            return nextIndex > 0;
        }

        public E previous() {
            checkForComodification();
            if (!hasPrevious())
                throw new NoSuchElementException();

            lastReturned = next = (next == null) ? last : next.prev;
            nextIndex--;
            return lastReturned.item;
        }

        public int nextIndex() {
            return nextIndex;
        }

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

        public void remove() {
            checkForComodification();
            if (lastReturned == null)
                throw new IllegalStateException();

            Node<E> lastNext = lastReturned.next;
            unlink(lastReturned);
            if (next == lastReturned)
                next = lastNext;
            else
                nextIndex--;
            lastReturned = null;
            expectedModCount++;
        }

        public void set(E e) {
            if (lastReturned == null)
                throw new IllegalStateException();
            checkForComodification();
            lastReturned.item = e;
        }

        public void add(E e) {
            checkForComodification();
            lastReturned = null;
            if (next == null)
                linkLast(e);
            else
                linkBefore(e, next);
            nextIndex++;
            expectedModCount++;
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

对于remove操作的思路大体一致只不过把lastRet换成了一个链表节点lastReturned,在每次remove后也会将其置位null。而在获取元素上不是像父类版本中的那样直接通过get(i)进行获取。迭代器会保存两个相邻的节点指针lastReturned和next。这样当元素被remove掉(lastReturned=null),当再次调用next时由于保存了next指针值,依然可以在链表中移动。

 

相比于Iterator接口ListIterator接口多了一个add方法,它会把元素放入到迭代器指向的next元素之前的位置,即下一个元素之前的位置。

Iterable接口

public interface Iterable<T> {

    /**
     * Returns an iterator over a set of elements of type T.
     *
     * @return an Iterator.
     */
    Iterator<T> iterator();
}

如Java Core上所述如果我们实现Iterable接口那么就可以在foreach循环中使用。如

class MyCollection implements Iterable<Integer> {

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            public int count = 0;

            @Override
            public boolean hasNext() {

                return count < 10;
            }

            @Override
            public Integer next() {
                return count++;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }

        };
    }

}

public class Fields implements Const {
    public static void main(final String[] args) {

        MyCollection myCollection = new MyCollection();
        for (Integer i : myCollection) {
            System.out.println(i);
        }

    }
}

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。