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

來源:互聯網
上載者:User

標籤:

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 call10          * to remove.11          */12         int lastRet = -1;13 14         /**15          * The modCount value that the iterator believes that the backing16          * List should have.  If this expectation is violated, the iterator17          * 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);        }    }}

 

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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.