Iterator迭代删除的注意事项
2018-01-03 16:41
309 查看
1、Iterator介绍
Iterator 用同一种逻辑来遍历集合。使得客户端自身不需要来维护集合的内部结构,所有的内部状态都由Iterator来维护。客户端从不直接和集合类打交道,它总是控制Iterator,向它发送"向前","向后","取当前元素"的命令,就可以间接遍历整个集合。在Java中Iterator为一个接口,它只提供了迭代了基本规则,在JDK中他是这样定义的:对 collection 进行迭代的迭代器。
接口定义为:
public interface Iterator{
boolean hasNext();
Object next();
void remove();
}
其中:
Object next():返回迭代器刚越过的元素的引用,返回值是Object,需要强制转换成自己需要的类型
boolean hasNext():判断容器内是否还有可供访问的元素
void remove():删除迭代器刚越过的元素
2、ArrayList的Iterator实现。
在 ArrayList 内部首先是定义一个内部类 Itr,该内部类实现 Iterator 接口,如下:private class Itr implements Iterator<E> {
//....
}
在内部类实现了Iterator接口,而ArrayList的Iterator是返回的它的内部类Itr,所以我们主要看看Itr是如何实现的。
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor; // 下一个元素的索引位置
int lastRet = -1; // 上一个元素的索引位置; -1 if no such
int expectedModCount = modCount; //修改的次数 modCount,记录了ArrayList结构性变化的次数
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
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();
}
}
final void checkForComodification() {
if (expectedModCount != ArrayList.this.modCount)
throw new ConcurrentModificationException();
}
}
1、expectedModCount的初值为modCount
2、hasNext的判断条件为cursor!=size,就是当前迭代的位置不是数组的最大容量值就返回true
3、next和remove操作之前都会先调用checkForComodification来检查expectedModCount和modCount是否相等
如果没checkForComodification去检查expectedModCount与modCount相等,这个程序肯定会报ArrayIndexOutOfBoundsException
3 测试Iterator
public static void main(String[] args) {List<String> stringList= new ArrayList<String>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
stringList.add("d");
Iterator<String> it = stringList.iterator();
while(it.hasNext()){
String str = it.next();
if(str.contains("c")){
stringList.remove(str);
}else {
logger.info("str:==========={}",str);
}
}
}
输出结果为:
str:===========a
str:===========b
d并没有输出, 因为在删除 c 的时候cursor为3,size也变成了3。所以hasNext就返回为false了,循环结束,从而后面的元素也不会输出了.
将stringList.remove(str); 改为 it.remove()
输出结果为:
str:===========a
str:===========b
str:===========d
因为iterator 的remove 方法,在删除当前元素的同时,将 cursor 置为了 2 并且将 expectedModCount 设为 modCount; 维护了索引的一致性,而当前的size=3 所以 hasNext方法返回为true,循环继续,所以将d正常输出了。
整个过程 cursor、lastRet 、expectedModCount、size 的值变化为 (0 -1 4 4 ) ——>(1 0 4 4)输出a ——> (2 1 4 4)输出b——> (3 2 4 4 )删除c ——>(2 -1 5 3 )——>(3 2 5 3 )输出d——>cursor=size 循环结束
相关文章推荐
- 对List元素迭代删除的注意事项以及三个方法
- c++ iterator 删除的注意事项
- 从PHP5到PHP7的注意事项(4)PHP7全面删除Mysql扩展支持
- Hql语句注意事项总结 批量删除 批量查询
- Iterator递归迭代实例。剪切文件并删除文件夹
- hibernate级联删除的注意事项
- ormlite 删除对象时注意事项
- 对于Git中用命令删除分支时的注意事项
- No known class method for selector 'setImage:andName:'错误分析.//删除.h与.m文件时的注意事项
- 删除元素【C++】顺序容器 Vector 注意事项
- 调用平台删除选择行数据方法注意事项
- map中的迭代删除操作注意问题
- git删除文件需要注意的事项
- Iterator使用及ArrayList遍历注意事项
- MySQL的MYISAM格式的库,进行大批量删除数据注意事项
- cocos2d一些注意事项及vector删除对象的方法
- OGNL iterator注意事项
- 调用平台删除选择行数据方法注意事项
- python 删除某个路径下所有文件及模块调用注意事项
- 删除索引DeleteDocuments:Lucene.Net 删除索引DeleteDocuments的注意事项