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);
    }
    
    
  • 相关阅读:
    win10 uwp 弹起键盘不隐藏界面元素
    win10 uwp 存放网络图片到本地
    win10 uwp 存放网络图片到本地
    sublime Text 正则替换
    sublime Text 正则替换
    win10 uwp 绘图 Line 控件使用
    win10 uwp 绘图 Line 控件使用
    AJAX 是什么?
    什么是 PHP SimpleXML?
    PHP XML DOM:DOM 是什么?
  • 原文地址:https://www.cnblogs.com/swifthao/p/12863355.html
Copyright © 2011-2022 走看看