for循环遍历删除数据的异常及modCount的作用
2017-08-24 11:21
417 查看
[b]这篇博文主要记录下面几个问题:[/b]
[b]1、for循环遍历能不能删除数据不报错。普通for循环(for(int i=0;i<list.size;i++)) 可以;加强型不可以(for(String str:list))原因下面会解释[/b]
[b]2、迭代器能不能删除数据。可以(如果你没有使用错误的话)错误的情况下面也会解释[/b]
首先看for循环删除集合元素的情况:
1、普通for循环删除元素:
List<String> list = new ArrayList<String>();
list.add("one");
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
list.add("six");
for(int i=0;i<list.size();i++){
String temp = list.get(i);
if(temp.equals("one")){
list.remove(i);
}
}
System.out.println(list);
这段代码运行是不会报异常的,但是打印的内容有点问题,只删除了一个“one”还有一个“one”,导致的原因就是i++; 因为删除第一个元素“one”的时候,第二个元素“one”变成了第一个元素,也就是整体向前移动一位,删除源码:
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
也就是index=0了,而此时for循环里i++,i=1了,这是就遍历不到index=0的这个位置了,所以删除不了,但是稍微修改下还是可以删除的,代码做如下调整:
List<String> list = new ArrayList<String>();
list.add("one");
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
list.add("six");
for(int i=0;i<list.size();i++){
String temp = list.get(i);
if(temp.equals("one")){
list.remove(i);
i--;
}
}
System.out.println(list);满足条件时添加i--;将下标回退下,就可以遍历到每个位置了;
2、加强型for循环删除元素:
List<String> list = new ArrayList<String>();
list.add("one");
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
list.add("six");
for(String ss:list){
if(ss.equals("one")){
list.remove(ss);
}
}
System.out.println(list);这个代码是会报异常的:
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 com.auto.zjl.thread.Test.main(Test.java:36)原因下面再说,接着看用迭代器的操作:
List<String> list = new ArrayList<String>();
list.add("one");
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
list.add("six");
Iterator<String> it = list.iterator();
while(it.hasNext()){
String str = it.next();
if(str.equals("one")){
//1:迭代器删除 it.remove();
//2:列表删除 list.remove(str);
}
}
System.out.println(list);上面的两种删除方式 1:迭代器删除是可以成功的;2:列表删除是失败的,会报上面的那个异常
下面说说原因:
1、加强型for循环用的也是迭代器
2、迭代器的删除方法是有更新modCount的,源码:
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();
}
}
可以看到这条语句expectedModCount = modCount;而上面那个异常则是 对这两个值的比较,不同的时候报的异常:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}这里的迭代器用的也是list的remove:语句:ArrayList.this.remove(lastRet);源码:
可以看到 modCount++; 即每次都会修改这个值;现在回过头来看下:迭代器删除的那两种方式
//1:迭代器删除 it.remove();
//2:列表删除 list.remove(str);观察下上面的两个方法的源码就会发发现,迭代器的删除方法是有更新要比较的值的:expectedModCount = modCount;
而集合的删除是没有同步内部迭代器的值的;所以在使用迭代器删除的时候,误用了集合的删除方法是会报异常的,而加强型for循环用的就是迭代器,但是删除又只能用list.remove();所以是不行的;
但为什么每次修改都有记录modCount呢:ArrayList是非线程安全的,在操作过程中如果有别的线程修改集合内容,那集合数据可能就不准确了,这时候抛出异常避免继续执行可以看做是个快速失败的方法(个人理解)
[b]1、for循环遍历能不能删除数据不报错。普通for循环(for(int i=0;i<list.size;i++)) 可以;加强型不可以(for(String str:list))原因下面会解释[/b]
[b]2、迭代器能不能删除数据。可以(如果你没有使用错误的话)错误的情况下面也会解释[/b]
首先看for循环删除集合元素的情况:
1、普通for循环删除元素:
List<String> list = new ArrayList<String>();
list.add("one");
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
list.add("six");
for(int i=0;i<list.size();i++){
String temp = list.get(i);
if(temp.equals("one")){
list.remove(i);
}
}
System.out.println(list);
这段代码运行是不会报异常的,但是打印的内容有点问题,只删除了一个“one”还有一个“one”,导致的原因就是i++; 因为删除第一个元素“one”的时候,第二个元素“one”变成了第一个元素,也就是整体向前移动一位,删除源码:
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
也就是index=0了,而此时for循环里i++,i=1了,这是就遍历不到index=0的这个位置了,所以删除不了,但是稍微修改下还是可以删除的,代码做如下调整:
List<String> list = new ArrayList<String>();
list.add("one");
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
list.add("six");
for(int i=0;i<list.size();i++){
String temp = list.get(i);
if(temp.equals("one")){
list.remove(i);
i--;
}
}
System.out.println(list);满足条件时添加i--;将下标回退下,就可以遍历到每个位置了;
2、加强型for循环删除元素:
List<String> list = new ArrayList<String>();
list.add("one");
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
list.add("six");
for(String ss:list){
if(ss.equals("one")){
list.remove(ss);
}
}
System.out.println(list);这个代码是会报异常的:
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 com.auto.zjl.thread.Test.main(Test.java:36)原因下面再说,接着看用迭代器的操作:
List<String> list = new ArrayList<String>();
list.add("one");
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
list.add("six");
Iterator<String> it = list.iterator();
while(it.hasNext()){
String str = it.next();
if(str.equals("one")){
//1:迭代器删除 it.remove();
//2:列表删除 list.remove(str);
}
}
System.out.println(list);上面的两种删除方式 1:迭代器删除是可以成功的;2:列表删除是失败的,会报上面的那个异常
下面说说原因:
1、加强型for循环用的也是迭代器
2、迭代器的删除方法是有更新modCount的,源码:
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();
}
}
可以看到这条语句expectedModCount = modCount;而上面那个异常则是 对这两个值的比较,不同的时候报的异常:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}这里的迭代器用的也是list的remove:语句:ArrayList.this.remove(lastRet);源码:
public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; }
可以看到 modCount++; 即每次都会修改这个值;现在回过头来看下:迭代器删除的那两种方式
//1:迭代器删除 it.remove();
//2:列表删除 list.remove(str);观察下上面的两个方法的源码就会发发现,迭代器的删除方法是有更新要比较的值的:expectedModCount = modCount;
而集合的删除是没有同步内部迭代器的值的;所以在使用迭代器删除的时候,误用了集合的删除方法是会报异常的,而加强型for循环用的就是迭代器,但是删除又只能用list.remove();所以是不行的;
但为什么每次修改都有记录modCount呢:ArrayList是非线程安全的,在操作过程中如果有别的线程修改集合内容,那集合数据可能就不准确了,这时候抛出异常避免继续执行可以看做是个快速失败的方法(个人理解)
相关文章推荐
- 复习 使用for、while循环遍历文件,数据类型转换
- 关于swift for 循环 遍历数组删除元素的bug问题
- Python中list循环遍历中删除数据报溢出异常
- JS中数据结构的遍历--Iterator和for...of循环
- EF实体生成关系导致相互循环取数据出现异常"Self referencing loop detected for property "
- 安卓删除List里面某些一样的数据为何使用的是迭代器而不是for循环
- SQL循环遍历,删除表里某一列是重复的数据,只保留一条。
- Python的list循环遍历中,删除数据的正确方法
- ArrayList循环遍历并删除元素时报java.util.ConcurrentModificationException异常
- 复习 使用for、while循环遍历文件,数据类型转换
- JS 循环遍历JSON数据
- Spring+Mybatis 查询所有数据时发生异常:org.apache.ibatis.reflection.ReflectionException: There is no getter for
- for 循环遍历数组
- 20.购物车商品价格的总和(里面有一些功能没有实现,创建textview布局对象,然后for()遍历数据求和)
- ORACLE 中 FOR 语句循环插入数据
- for循环数据节点
- for/in 循环遍历对象的属性
- 单循环链表的初始化、创建、删除、查找与遍历
- hibernate先删除数据,紧接着执行插入时的异常解决之道——中间不能调用flush()、clear()等方法
- python快速入门 数据输出和基本类型 常用的循环遍历等