zoukankan      html  css  js  c++  java
  • Java--Iterator和Iterable

    Iterator接口

    Iterator接口来自java.util包,主要方法如下:

    package java.util;
    
    public interface Iterator<E> {
        
        boolean hasNext();
        
        E next();
        
        default void remove() {
            throw new UnsupportedOperationException("remove");
        }
        
    }
    

    Iterable接口

    Iterable接口来自java.lang包,实现了Iterable接口的类可以使用for each去遍历

    Iterable接口通过iterator()方法返回一个Iterator实例

    package java.lang;
    
    /**
     * Implementing this interface allows an object to be the target of
     * the "for-each loop" statement.
     */
    public interface Iterable<T> {
        /**
         * Returns an iterator over elements of type
         *
         * @return an Iterator.
         */
        Iterator<T> iterator();
    
        /**
         * @param action The action to be performed for each element
         * @throws NullPointerException if the specified action is null
         * @since 1.8
         */
        default void forEach(Consumer<? super T> action) {
            Objects.requireNonNull(action);
            for (T t : this) {
                action.accept(t);
            }
        }
    
    }
    

    为什么要把Iterable和Iterator变成两个接口呢?

    因为实现了Iterable接口的类可以实现多个Iterator内部类,比如LinkedList中的ListItr和DescendingIterator这两个内部类,分别实现了链表的双向遍历和逆序遍历。通过返回不同的Iterator实例来实现不同的遍历方式,这样更灵活,如果将Iterable和Iterator合并,就没法返回不同的Iterator实例。Iterable相当于对Iterator的封装

    Iterator的保留可以让子类去实现自己的迭代器,而Iterable接口更加关注于for each

    LinkedList类中的这两个内部类如下:

    package java.util;
    
    public class LinkedList<E>
            extends AbstractSequentialList<E>
            implements List<E>, Deque<E>, Cloneable, java.io.Serializable
    {
        //省略了其他实现,只显示了这两个内部类的代码
    
        public ListIterator<E> listIterator(int index) {
            checkPositionIndex(index);
            return new ListItr(index);
        }
    
        private class ListItr implements ListIterator<E> {
            private LinkedList.Node<E> lastReturned;
            private LinkedList.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();
    
                LinkedList.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++;
            }
    
            public void forEachRemaining(Consumer<? super E> action) {
                Objects.requireNonNull(action);
                while (modCount == expectedModCount && nextIndex < size) {
                    action.accept(next.item);
                    lastReturned = next;
                    next = next.next;
                    nextIndex++;
                }
                checkForComodification();
            }
    
            final void checkForComodification() {
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
            }
        }
    
    
        public Iterator<E> descendingIterator() {
            return new DescendingIterator();
        }
    
        /**
         * Adapter to provide descending iterators via ListItr.previous
         */
        private class DescendingIterator implements Iterator<E> {
            private final LinkedList.ListItr itr = new LinkedList.ListItr(size());
            public boolean hasNext() {
                return itr.hasPrevious();
            }
            public E next() {
                return itr.previous();
            }
            public void remove() {
                itr.remove();
            }
        }
    
    }
    

    总结

    Java容器中,所有的Collection子类会实现Iteratable接口以实现foreach功能,Iteratable接口的实现又依赖于实现了Iterator的内部类(参照LinkedList中listIterator()和descendingIterator()的JDK源码)。有的容器类会有多个实现Iterator接口的内部类,通过返回不同的迭代器实现不同的迭代方式。


    扩展:ListIterator接口

    ListIterator的注意点:

    • 实现了Iterator接口
    • 以任意方向遍历List
    • 在遍历的时候修改list
    • 获取iterator在list中的当前位置
    • ListIterator没有当前的元素,它光标的位置总是在previous()和next()之间
    • 长度为n的list有n+1种可能的光标位置

    代码如下,注意读注释:

    package java.util;
    
    /**
     * An iterator for lists that allows the programmer
     * to traverse the list in either direction, modify
     * the list during iteration, and obtain the iterator's
     * current position in the list. A {@code ListIterator}
     * has no current element; its <I>cursor position</I> always
     * lies between the element that would be returned by a call
     * to {@code previous()} and the element that would be
     * returned by a call to {@code next()}.
     * An iterator for a list of length {@code n} has {@code n+1} possible
     * cursor positions, as illustrated by the carets ({@code ^}) below:
     * <PRE>
     *                      Element(0)   Element(1)   Element(2)   ... Element(n-1)
     * cursor positions:  ^            ^            ^            ^                  ^
     * </PRE>
     * Note that the {@link #remove} and {@link #set(Object)} methods are
     * <i>not</i> defined in terms of the cursor position;  they are defined to
     * operate on the last element returned by a call to {@link #next} or
     * {@link #previous()}.
     *
     */
    public interface ListIterator<E> extends Iterator<E> {
    
        //Query Operations
    
        /**
         * Returns {@code true} if this list iterator has more elements when
         * traversing the list in the forward direction.
         */
        boolean hasNext();
    
        /**
         * Returns the next element in the list and advances the cursor position.
         * @return the next element in the list
         * @throws NoSuchElementException if the iteration has no next element
         */
        E next();
    
        /**
         * Returns {@code true} if this list iterator has more elements when
         * traversing the list in the reverse direction.
         */
        boolean hasPrevious();
    
        /**
         * Returns the previous element in the list and moves the cursor
         * position backwards.
         * @return the previous element in the list
         * @throws NoSuchElementException if the iteration has no previous
         *         element
         */
        E previous();
    
        /**
         * Returns the index of the element that would be returned by a
         * subsequent call to {@link #next}. (Returns list size if the list
         * iterator is at the end of the list.)
         *
         * @return the index of the element that would be returned by a
         *         subsequent call to {@code next}, or list size if the list
         *         iterator is at the end of the list
         */
        int nextIndex();
    
        /**
         * Returns the index of the element that would be returned by a
         * subsequent call to {@link #previous}. (Returns -1 if the list
         * iterator is at the beginning of the list.)
         *
         * @return the index of the element that would be returned by a
         *         subsequent call to {@code previous}, or -1 if the list
         *         iterator is at the beginning of the list
         */
        int previousIndex();
    
    
        // Modification Operations
    
        /**
         * Removes from the list the last element that was returned by {@link
         * #next} or {@link #previous} (optional operation).  This call can
         * only be made once per call to {@code next} or {@code previous}.
         * It can be made only if {@link #add} has not been
         * called after the last call to {@code next} or {@code previous}.
         */
        void remove();
    
        /**
         * Replaces the last element returned by {@link #next} or
         * {@link #previous} with the specified element (optional operation).
         * This call can be made only if neither {@link #remove} nor {@link
         * #add} have been called after the last call to {@code next} or
         * {@code previous}.
         */
        void set(E e);
    
        /**
         * Inserts the specified element into the list (optional operation).
         * The element is inserted immediately before the element that
         * would be returned by {@link #next}, if any, and after the element
         * that would be returned by {@link #previous}, if any.  (If the
         * list contains no elements, the new element becomes the sole element
         * on the list.)  The new element is inserted before the implicit
         * cursor: a subsequent call to {@code next} would be unaffected, and a
         * subsequent call to {@code previous} would return the new element.
         * (This call increases by one the value that would be returned by a
         * call to {@code nextIndex} or {@code previousIndex}.)
         */
        void add(E e);
    }
    
    
  • 相关阅读:
    第k短路
    Codeforces Round #608 (Div. 2)
    Codeforces Round #606 E(无向图求pair(x,y)x到y的任意路径一定经过定点a和b的数量)
    Codeforces Round #603 (Div. 2)E
    题解报告:hdu 2717 Catch That Cow(bfs)
    题解报告:poj 3669 Meteor Shower(bfs)
    题解报告:poj 1321 棋盘问题(dfs)
    题解报告:hdu 1312 Red and Black(简单dfs)
    题解报告:poj 1426 Find The Multiple(bfs、dfs)
    hdu 4704 Sum(扩展欧拉定理)
  • 原文地址:https://www.cnblogs.com/swifthao/p/12863355.html
Copyright © 2011-2022 走看看