Iterator通常用来遍历集合元素,如在for循环中:
List<String> sList = new ArrayList<String>();
for (Iterator<String> it = sList.iterator(); it.hasNext();) {
String string = it.next();
// do something
}
另一种更加优雅的写法是
增强的 for 循环:foreach,这个特性是在Java 5 中加入的:
List<String> sList = new ArrayList<String>();
for (String str : sList) {
// do something
}
编译器在编译foreach时会自动生成字节码“invokeinterface java.util.Iterator java.util.List.iterator()”,ArrayList的iterator()方法返回ArrayList内置的私有类Itr,Itr则实现了Iterator接口:
/**
* Returns an iterator over the elements in this list in proper sequence.
*
* <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
*
* @return an iterator over the elements in this list in proper sequence
*/
public Iterator<E> iterator() {
return new Itr();
}
java编译器还会生成字节码“invokeinterface java.lang.Object java.util.Iterator.next()”和“invokeinterface boolean java.util.Iterator.hasNext()”来遍历Itr。
但是滥用foreach的话会产生异常,如下代码:
List<String> strList = new ArrayList<String>();
for (String string : strList) {
strList.remove(string);
}
在循环中删除元素会抛出ConcurrentModificationException:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at Main.main(Main.java:19)
这是由于
Java Collections FrameWork 的fail-fast机制导致的,因为在迭代过程中还进行了删除操作,导致列表的结构发生了改变,然后在调用next()方法时会去调用checkForComodification()进行check时就会抛出异常:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
解决办法是调用Iterator的remove方法,该方法会在删除当前元素的同时去维护迭代器索引的一致性,如ArrayList$Itr.remove()的实现:
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
其中第10行就是为了确保索引的一致性。所以
Iterator还可以确保remove操作的安全性。
Iterator的另一个好用的地方是ListIterator,ListIterator继承了Iterator,并支持对Iterator的双向操作,这种双向遍历在很多情况下方便我们的操作,如Collections.reverse()中就有对ListIterator的运用:
public static void reverse(List<?> list) {
int size = list.size();
if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
swap(list, i, j);
} else {
ListIterator fwd = list.listIterator();
ListIterator rev = list.listIterator(size);
for (int i=0, mid=list.size()>>1; i<mid; i++) {
Object tmp = fwd.next();
fwd.set(rev.previous());
rev.set(tmp);
}
}
}
reverse方法是对list进行反序操作,其中的fwd是把cursor(下一个元素的索引)定位到list的起始位置,而rev则是把cursor定位到list的结尾,这样就可以把起始元素和结尾元素进行对调从而达到反序的效果。