對于我們常用的ArrayList等容器類,經常需要一個一個遍歷里面的元素,從而對各個元素執行對應的操作。
像我代碼寫多了,通常的做法是用傳統的,類似于數組遍歷的方法,即在for循環中設置一個int變量作為索引,然后用List的get方法,想怎么做就怎么做,不會遇到任何不能做的事。
當然,偶爾我會寫得簡單一點,用 for (元素類型變量名 :集合) 的方法,即不用索引,直接指定實際的元素類型,取下一個元素,這樣可以少寫一行代碼。
但不管用哪一種,我都沒有考慮過用迭代器iterator,雖然教程上面經常提到這東西,我也知道這是用來遍歷,順便執行刪除等操作的。因為用類似數組遍歷的方法取元素從未遇到過瓶頸,就從來沒研究過iterator,也一直都覺得這是個沒有卵用的東西。
最近在研究ArrayList和LinkedList源碼的時候,源碼里面也有很大一段是關于Iterator的,這讓我更加不解了:既然是一個可有可無可替代的東西,為什么官方還要費這么大的勁來描述它呢?
直到最近閱讀《Effective Java》,看了一節關于for-each和傳統for循環的比較,里面有一句話讓我重新審視Iterator:
Not only does the for-each loop let you iterate over collections and arrays,
it lets you iterate over any object that implements the Iterable interface.
這就不得不讓我懷疑:難道我以前所知道的集合類,就是因為實現了Iterable接口,才可以用for加冒號的方式?
google了一下,果然,for-each這樣一種簡潔的書寫方式,內部居然就是用迭代器實現的!
下面的代碼摘自StackOverFlow
List<String> someList = new ArrayList<String>();
正常的用for-each遍歷方法:
for (String item : someList) { System.out.PRintln(item);}重點來了,上面這簡單的一句話,在編譯過程中,被編譯器自動翻譯成了下面這段,真正執行的時候也正是下面這段:
for(Iterator<String> i = someList.iterator(); i.hasNext(); ) { String item = i.next(); System.out.println(item);}
所以,在實際開發中,雖然明面上很少用到標標準準的Iterator,但是常用的for-each的暗箱操作卻都是Iterator!
Java創造出來for-each的操作,好處之一當然是簡化了代碼的書寫,減少了變量個數。
另外還有很重要的一點是大大降低了遍歷過程當中的誤操作。想想看,如果在for-each過程中,你得到了當前位置的元素值,有什么辦法可以添加、刪除或修改元素值呢?答案是沒有。然而利用Iterator或者索引來寫循環,你可以進行幾乎所有的增刪改操作。所以利用for-each來操作更安全。
當然,for-each還有一種用法,即用在普通數組的遍歷當中,當中也進行了暗箱操作,即轉換為索引的遍歷。
int[] test = new int[] {1,4,5,7};for (int intValue : test) { // do some work here on intValue}
編譯時轉換為:
int[] test = new int[] {1,4,5,7};for (int i = 0; i < test.length; i++) { int intValue = test[i]; // do some work here on intValue}一定要注意,for-each只能用于:①Iterable ②數組
也即,除了數組以外,一般的類只要實現了Iterable接口就能用for-each
我們可以隨便寫個類玩玩。
import java.util.Iterator;public class MyClass<E> implements Iterable<E>{ private class MyIterator implements Iterator<E> { private int max = 10; private int cur = 0; @Override public boolean hasNext() { if (cur < max) return true; else return false; } @SuppressWarnings("unchecked") @Override public E next() { Object res = ++cur; return (E) res; } @Override public void remove() { System.out.println("索引:"+cur+" 被刪除"); } }; @Override public Iterator<E> iterator() { return new MyIterator(); } }測試下
import java.util.Iterator;public class JavaMain { public static void main(String[] args) { MyClass<Integer> m = new MyClass<>(); for (Integer i : m) { System.out.println(i); } System.out.println("-------------------------------------------"); for (Iterator<Integer> it = m.iterator();it.hasNext();) { Integer val = it.next(); if (val % 3 == 0) it.remove(); } } }輸出結果:
12345678910-------------------------------------------索引:3 被刪除索引:6 被刪除索引:9 被刪除
我們這里的MyClass類沒有任何實際的意義,居然試驗成功了,真是一件不可思議的事情。。。
參考資料:
http://stackoverflow.com/questions/85190/how-does-the-java-for-each-loop-work
http://docs.Oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2
新聞熱點
疑難解答