從Java5起,在Java中有了for-each循環,能夠用來循環遍歷collection和array。For each循環容許你在無需保持傳統for循環中的索引,或在使用iterator /ListIterator時無需調用while循環中的hasNext()方法就能遍歷collection。Java中,for-each循環簡化了任何Collection或array的遍歷過程,但並非每一個Java程序員都瞭解本文將要描述的for-each 循環的一些細節。與 Java5 發佈的其餘術語:釋放別名泛型,自動封裝和可變參數不一樣,Java開發者對for-each循環的使用比任何其餘特性更加頻繁,但當問及高級的for-each循環怎樣工做,或什麼是在for-each循環中使用Collection時的基本需求時,就不是每一個人都可以回答的了。本篇教程和例子旨在經過深刻研究for-each 循環中幾個有趣的難題來填補上述空白(說明上述問題)。好了,再也不贅述,一塊兒看看咱們在Java5 for-each循環的第一個問題。 java
考慮下面這段遍歷一個用戶自定義的aggregator或collection類的代碼,這段代碼將會打印出什麼,拋出異常仍是編譯器錯誤: 程序員
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
packagetest;
/**
* Java Class to show how for-each loop works in Java
*/
publicclassForEachTest {
publicstaticvoidmain(String args[]){
CustomCollection<String> myCollection =newCustomCollection<String>();
myCollection.add("Java");
myCollection.add("Scala");
myCollection.add("Groovy");
//What does this code will do, print language, throw exception or compile time error
for(String language: myCollection){
System.out.println(language);
}
}
}
|
下面是咱們的CustomCollection類,這是個參數爲泛型的類,與任何其餘的Collection類類似,依靠於ArrayList並提供從Collection中添加和刪除項的方法。 express
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
packagetest;
publicclassCustomCollection<T>{
privateArrayList<T> bucket;
publicCustomCollection(){
bucket =newArrayList();
}
publicintsize() {
returnbucket.size();
}
publicbooleanisEmpty() {
returnbucket.isEmpty();
}
publicbooleancontains(T o) {
returnbucket.contains(o);
}
publicbooleanadd(T e) {
returnbucket.add(e);
}
publicbooleanremove(T o) {
returnbucket.remove(o);
}
}
|
答案: app
上述代碼將沒法經過編譯,這是由於咱們的CustomCollection類沒有實現java.lang.Iterable接口,編譯期錯誤以下: oop
1
2
3
4
5
|
Exceptioninthread"main"java.lang.RuntimeException: Uncompilablesourcecode -for-each not applicable to expressiontype
required: array or java.lang.Iterable
found:test.CustomCollection
attest.ForEachTest.main(ForEachTest.java:24)
|
從中瞭解到的一個有趣的事實是:for-each循環僅應用於實現了Iterable接口的Java array和Collection類,並且既然全部內置Collection類都實現了java.util.Collection接口,已經繼承了Iterable,這一細節一般會被忽略,這點能夠在Collection接口的類型聲明「 public interface Collection extends Iterable」中看到。因此爲了解決上述問題,你能夠選擇簡單地讓CustomCollection實現Collection接口或者繼承AbstractCollection,這是默認的通用實現並展現瞭如何同時使用抽象類和接口以獲取更好的靈活性。如今讓咱們來看看for-each循環的第二個難題: ui
在下面的代碼示例將會拋出ConcurrentModificationException異常。這裏咱們使用標準iterator和for-each循環遍歷ArrayList,隨後刪除元素,你須要找出哪段代碼將會拋出ConcurrentModificationException ,爲何?請注意,答案多是兩個都會,都不會或其中之一。 this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
packagetest;
importjava.util.ArrayList;
importjava.util.Collection;
importjava.util.Iterator;
/**
* Java class to demonstrate inner working of for-each loop in Java
*
@author Javin Paul
**/
publicclassForEachTest2 {
publicstaticvoidmain(String args[]){
Collection<String> list =newArrayList<String>();
list.add("Android");
list.add("iPhone");
list.add("Windows Mobile");
// Which Code will throw ConcurrentModificationException, both,
// none or one of them
// example 1
Iterator<String> itr = list.iterator();
while(itr.hasNext()){
String lang = itr.next();
list.remove(lang);
}
// example 2
for(String language: list){
list.remove(language);
}
}
}
|
大約70%的Java開發者都會說第一個代碼塊會拋出ConcurrentModificationException異常,由於咱們沒有用iterator的remove方法來刪除元素,而是使用ArrayList的 remove()方法。可是,沒有多少Java開發者會說出for-each循環也會出現一樣的問題,由於咱們在這裏沒有使用iterator。事實上,第二個代碼片斷也會拋出ConcurrentModificationException異常,這點在解決了第一個困惑以後就變得很明顯了。既然for-each循環內部使用了Iterator來遍歷Collection,它也調用了Iterator.next(),這會檢查(元素的)變化並拋出ConcurrentModificationException。你能夠從下面的輸出中瞭解到這點,在註釋掉第一個代碼段後,當你運行第二個代碼段時會獲得下面的輸出。 spa
1
2
3
4
|
Exceptioninthread"main"java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
attest.ForEachTest2.main(ForEachTest2.java:34)
|
以上就是關於Java5 for-each循環的所有內容。咱們已經看到了Java程序員在編寫遍歷Collection類的代碼時產生的不少問題,特別是在遍歷collection的同時刪除元素的時候。請牢記,在從任何Collection(例如Map、Set或List)中刪除對象時總要使用Iterator的remove方法,也請謹記for-each循環只是標準Iterator代碼標準用法之上的一種語法糖(syntactic sugar)而已。 .net
譯者注:語法糖(syntactic sugar),也譯爲糖衣語法,是由英國計算機科學家彼得·約翰·蘭達-Peter J. Landin發明的一個術語,指計算機語言中添加的某種語法,這種語法對語言的功能並無影響,可是更方便程序員使用。一般來講使用語法糖可以增長程序的可讀性,從而減小程序代碼出錯的機會。 code