Java叠代器Iterator
之前我們實現了叠代器模式,很多編程語言實際上已經內置了叠代器類,比如Java就為我們實現了叠代器Iterator。我們首先來看Iterator中的源碼。
通過JDK源碼我們發現Iterator是一個接口,包含三個方法:hasNext、next、remove。
1 package java.util; 2 3 public interface Iterator<E> { 4 5 /** 6 *如果叠代器中還有元素則返回true 7 */ 8 boolean hasNext(); 9 10 /**11 *返回叠代器中的下一個元素12 */13 E next();14 15 /**16 *通過叠代器刪除處於集合中最底層的元素17 */18 void remove();19 }
Iterator是一個接口,那如何來創建一個實例呢?要記住,叠代器和集合類的關系非常緊密,我們可以通過集合類來創建一個Iterator實例,ArrayList、LinkedList、Vector都有對它的實現。我們來看ArrayList是如何創建一個Iterator叠代器實例的。在此之前我們先來看看集合和叠代器之間的繼承關系。
由於集合的關系相對來說比較復雜,在此我們主要看註釋部分,通過閱讀源代碼會發現ArrayList覆寫了AbstractList抽象類中的iterator方法並聲稱效果更佳,而LinkedList則沒有覆寫,由此可判斷ArrayList的iterator方法比LinkedList中的iterator方法更為高效。
我們直接看ArrayList裏中實現的iterator方法。
1 public Iterator<E> iterator() {2 return new Itr();3 }
從代碼來看它返回類一個Itr的對象實例,順著代碼看看這個Itr類是什麽。
1 private class Itr implements Iterator<E> { 2 int cursor; // 返回下一個元素的索引 3 int lastRet = -1; // 返回最後一個元素的索引;如果沒有則返回-1 4 int expectedModCount = modCount; 5 6 public boolean hasNext() { 7 return cursor != size; 8 } 9 10 @SuppressWarnings("unchecked")11 public E next() {12 checkForComodification();13 int i = cursor;14 if (i >= size)15 throw new NoSuchElementException();16 Object[] elementData = ArrayList.this.elementData;17 if (i >= elementData.length)18 throw new ConcurrentModificationException();19 cursor = i + 1;20 return (E) elementData[lastRet = i];21 }22 23 public void remove() {24 if (lastRet < 0)25 throw new IllegalStateException();26 checkForComodification();27 28 try {29 ArrayList.this.remove(lastRet);30 cursor = lastRet;31 lastRet = -1;32 expectedModCount = modCount;33 } catch (IndexOutOfBoundsException ex) {34 throw new ConcurrentModificationException();35 }36 }37 38 final void checkForComodification() {39 if (modCount != expectedModCount)40 throw new ConcurrentModificationException();41 }42 }
原來Itr它是一個私有的內部類,實現Iterator接口。
我們來一行一行讀。在第3行中有一個modCount變量。跟蹤這個變量,發現這個變量有點意思:
protected transient int modCount = 0;
發現有一個“transient”關鍵字,查閱資料發現這個關鍵字的意思是:表示一個域不是該對象序列化的一部分。意思是在對象被序列化時不包括這個變量,至於為什麽要這麽做呢,我們可以留下一個疑問。(JDk源碼註釋中是這麽說的:The modCount value that the iterator believes that the backing List should have. If this expectation is violated, the iterator has detected concurrent modification.英語太次只能讀懂最後一句:如果這個期望是可見性的,那麽這個叠代器會檢測到有一個並發的修改。猜測是和並發多線程相關。)
hasnext的實現較為簡單:
1 public boolean hasNext() {2 return cursor != size; //下一個元素的索引是否等於ArrayList的大小3 }
next的實現:
public E next() { checkForComodification(); //檢查是否並發修改 int i = cursor; if (i >= size) throw new NoSuchElementException(); //索引大於ArrayList大小拋出異常 Object[] elementData = ArrayList.this.elementData; //後面實際是在取ArrayList中的數據 if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; }
在next方法中我們看到有一個checkForCommodification方法:
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
看來這個modCount變量確實是和並發相關,如果expectedModCount和modCount這兩個值不同,則拋出當前正在並發修改的異常。
最後我們來看remove方法的實現:
public void remove() { if (lastRet < 0) //這個地方格外註意,不能在未調用next時直接調用remove方法,必須在remove調用前調用next方法,將通過cursor索引值將其值賦給lastRet throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } }
在remove方法中我們要格外註意,在第一句是檢測lastRet是否小於0,我們初始化了lastRet變量-1的值,這意味著,如果我們如果創建完Iterator實例後直接調用remove方法會拋出一個IllegalStateException異常,那怎麽才能正確調用呢?那就是在調用remove方法前先調用next方法,此時lastReturn通過cursor索引被賦值,這個時候才能正確使用remove方法。同時它也會調用checkForCommodification方法做並發修改檢測。其實我們可以看到JDK源碼之所以寫到好,是因為它每個方法都做了很多的檢測,以確保在盡量多的場景下準確無誤地運行。今天關於Java的叠代器就通過JDK源碼簡單介紹,通過對源碼的閱讀能夠加深我們的理解,這還只是簡單的閱讀,並沒有做很深的理解。最後,我們以為一個Iterator的例子結尾。
1 package day_29_iterator; 2 3 import java.util.ArrayList; 4 import java.util.Iterator; 5 import java.util.List; 6 7 /** 8 * @author turbo 9 *10 * 2016年9月29日11 */12 public class Main {13 14 /**15 * @param args16 */17 public static void main(String[] args) {18 List list = new ArrayList();19 list.add(1);20 list.add(2);21 Iterator iterator = list.iterator();22 while (iterator.hasNext()){23 System.out.println(iterator.next());24 }25 }26 27 }
Java叠代器Iterator