浅谈Iterator的用处

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的结尾,这样就可以把起始元素和结尾元素进行对调从而达到反序的效果。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值