从Java5起,在Java中有了for-each循环,可以用来循环遍历collection和array。Foreach循环允许你在无需保持传统for循环中的索引,或在使用iterator /ListIterator(ArrayList中的一种迭代器实现)时无需调用while循环中的hasNext()方法就能遍历collection。for-each循环简化了任何Collection或array的遍历过程。但是使用foreach循环也有两点需要注意。
- 使用foreach循环的对象,必须实现了Iterable<T>接口
请看如下示例:
import java.util.ArrayList; public class ForeachTest1 { public static void main(String args[]) {
CustomCollection<String> myCollection = new CustomCollection<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);
}
} private class CustomCollection<T> {
private ArrayList<T> bucket; public CustomCollection() {
bucket = new ArrayList();
} public int size() {
return bucket.size();
} public boolean isEmpty() {
return bucket.isEmpty();
} public boolean contains(T o) {
return bucket.contains(o);
} public boolean add(T e) {
return bucket.add(e);
} public boolean remove(T o) {
return bucket.remove(o);
} }
}
上述代码将无法通过编译,这是因为代码中的CustomCollection类没有实现Iterable<T>接口,编译期的报错如下:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Can only iterate over an array or an instance of java.lang.Iterable at Text.ForeachTest1.main(ForeachTest1.java:15)
事实上,无需等到编译时才发现报错,eclipse会在这段代码写完之后就会在foreach循环处显示错误:Can only iterate over an array or an instance of java.lang.Iterable
从上述示例可以再次得到确认的是,foreach循环只适用于实现了Iterable<T>接口的对象。由于所有内置Collection类都实现了java.util.Collection接口,已经继承了Iterable,所以为了解决上述问题,可以选择简单地让CustomCollection实现Collection接口或者继承AbstractCollection。解决方式如下:
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Iterator; public class ForeachTest {
public static void main(String args[]) {
CustomCollection<String> myCollection = new CustomCollection<String>();
myCollection.add("Java");
myCollection.add("Scala");
myCollection.add("Groovy");
for (String language : myCollection) {
System.out.println(language);
}
} private static class CustomCollection<T> extends AbstractCollection<T> {
private ArrayList<T> bucket; public CustomCollection() {
bucket = new ArrayList();
} public int size() {
return bucket.size();
} public boolean isEmpty() {
return bucket.isEmpty();
} public boolean contains(Object o) {
return bucket.contains(o);
} public boolean add(T e) {
return bucket.add(e);
} public boolean remove(Object o) {
return bucket.remove(o);
} @Override
public Iterator<T> iterator() {
// TODO Auto-generated method stub
return bucket.iterator();
}
}
}
2.foreach循环的内部实现也是依靠Iterator进行实现的
为了验证foreach循环是使用Iterator作为内部实现这一事实,我们依然采用本文最开始的实例进行验证:
public class ItaratorTest { public static void main(String[] args) {
Collection<String> list = new ArrayList<String>();
list.add("Android");
list.add("IOS");
list.add("Windows Mobile"); // example1
// Iterator<String> iterator = list.iterator();
// while (iterator.hasNext()) {
// String lang = iterator.next();
// list.remove(lang);
// } // example 2
for (String language : list) {
list.remove(language);
}
} }
程序运行时所报异常:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at Text.ItaratorTest.main(ItaratorTest.java:22)
此异常正说明了for-each循环内部使用了Iterator来遍历Collection,它也调用了Iterator.next(),这会检查(元素的)变化并抛出ConcurrentModificationException。
总结:
- foreach循环通过iterator实现,使用foreach循环的对象必须实现Iterable接口