1.写出下面的输出结果

public class test{
  public static void main(String [] args)

   List<String> list = new ArrayList<String>();

   for (int i = 0; i < 10; i++) {
     list.add(String.valueOf(i));
   }
   for(String s : list){
    if(s.equals("3")){
      list.remove(s);
    }
   }
  System.out.println(list.size());

  }

}

正确的输出:发生了并发的错误

java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at test.main(test.java:35)

在这里for(String s : list){}的实质还是Iterator接口。

上面这段代码等价于下面:

Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
  String itString = (String)iterator.next();
  if (itString.equals("3")) {
    list.remove(itString); --这里会报错

    //iterator.remove();---这里不会报错

  }
}

所以我们来看看 list.iterator();的源码就知道为什么了

public Iterator<E> iterator() {
  return new Itr();
}

/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
  int cursor; // index of next element to return
  int lastRet = -1; // index of last element returned; -1 if no such
  int expectedModCount = modCount;

  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 (modCount != expectedModCount)
      throw new ConcurrentModificationException();
  }
}

从源码上我们可以看出,当我们调用next()方法的时候有一个检查modCount != expectedModCount;然后我们再来看看ArrayList的remove方法

public boolean remove(Object o) {
  if (o == null) {
    for (int index = 0; index < size; index++)
      if (elementData[index] == null) {
        fastRemove(index);
        return true;
      }
  } else {
  for (int index = 0; index < size; index++)
    if (o.equals(elementData[index])) {
      fastRemove(index);
      return true;
    }
  }
  return false;
}

/*
* Private remove method that skips bounds checking and does not
* return the value removed.
*/
private void fastRemove(int index) {
  modCount++;
  int numMoved = size - index - 1;
  if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
    numMoved);
  elementData[--size] = null; // Let gc do its work
}

从上面的代码中可以看出当我们进行remove的时候modeCount的值发生了变化,这就导致和expectedModCount的值相等了,故报错。

从源码中我们还得知,在clear方法,add方法,addAll方法,removeRange方法时都会导致modeCount的值发生变化。

所以当我们想在循环中对List进行删除时不能用List的remove*方法。但是可以用iterator.remove();从上面的源码中我们可以知道这个方法中进行了

expectedModCount=ModCount对expectedModCount重新赋值。

JAVA循环迭代中删除或添加集合数据报java.util.ConcurrentModificationException错误的更多相关文章

  1. 遍历List过程中删除操作报java.util.ConcurrentModificationException错误

    1:遍历List 同时 remove 元素,出现java.util.ConcurrentModificationException错误 @Test public void test3(){ List& ...

  2. Java循环遍历中直接修改遍历对象

    Java 循环遍历中直接修改遍历对象如下,会报异常: for (ShopBaseInfo sp: sourceList) { if(sp.getId()==5){ sourceList.remove( ...

  3. Java中删除第一个集合中以某某开头的元素,删除第二个集合中以某某结尾的元素,并合并成一个集合

    import java.util.ArrayList; import java.util.List; public class Test { public static void main(Strin ...

  4. 【java】TreeMap/HashMap的循环迭代中 keySet和entrySet和forEach方式 + map的几种迭代方式

    参考链接:https://www.cnblogs.com/crazyacking/p/5573528.html ================================== java紫色代表迭 ...

  5. java ArrayList迭代过程中删除

    第一种迭代删除方式: 第二种迭代删除方式: 第三种迭代删除: 第四种迭代删除: 第五种迭代删除: 第六种: ArrayList中remove()方法的机制,首先看源码: 真正的删除操作在fastRem ...

  6. cmd中删除、添加、修改注册表命令

    转自:http://www.jb51.net/article/30586.htm regedit的运行参数 REGEDIT [/L:system] [/R:user] filename1 REGEDI ...

  7. js实现在表格中删除和添加一行

    <!DOCTYPE html><html> <head> <title> new document </title> <meta ht ...

  8. For循环List中删除正确的方式

    单线程public class Test { public static void main(String[] args) { ArrayList<Integer> list = new ...

  9. Java 遍历List中删除的解决方法

随机推荐

  1. 设计模式 - 适配器模式(adapter pattern) 枚举器和迭代器 具体解释

    适配器模式(adapter pattern) 枚举器和迭代器 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考适配器模式(adapter patter ...

  2. 实战Java内存泄漏问题分析 -- hazelcast2.0.3使用时内存泄漏 -- 2

    hazelcast 提供了3中方法调用startCleanup: 第一种是在ConcuurentMapManager的构造函数中,通过调用node的executorManager中的Scheduled ...

  3. Adding Search

    https://docs.asp.net/en/latest/tutorials/first-mvc-app/search.html In this section you’ll add search ...

  4. Linux - 设置SFTP服务用户目录权限

    我们有时会遇到这样的需求,限制一个Linux用户,让他只能在指定的目录下进行添加.修改.删除操作,并且只能使用sftp登录服务器,不能用ssh操作.这些可以通过配置sftp服务实现. 创建新用户www ...

  5. Node.js:多进程

    ylbtech-Node.js:多进程 1.返回顶部 1. Node.js 多进程 我们都知道 Node.js 是以单线程的模式运行的,但它使用的是事件驱动来处理并发,这样有助于我们在多核 cpu 的 ...

  6. 【优化算法】遗传算法GA求解混合流水车间调度问题(附C++代码)

    00 前言 各位读者大家好,好久没有介绍算法的推文了,感觉愧对了读者们热爱学习的心灵.于是,今天我们带来了一个神奇的优化算法--遗传算法! 它的优点包括但不限于: 遗传算法对所求解的优化问题没有太多的 ...

  7. POJ 3620 DFS

    题意: 给你n*m的矩形,有k个坏点 问最大坏点连通块的坏点数. 一发水题.. 裸的DFS // by SiriusRen #include <cstdio> #include <a ...

  8. HBase编程 API入门系列之工具Bytes类(7)

    这是从程度开发层面来说,为了方便和提高开发人员. 这个工具Bytes类,有很多很多方法,帮助我们HBase编程开发人员,提高开发. 这里,我只赘述,很常用的! package zhouls.bigda ...

  9. Hadoop MapReduce编程 API入门系列之wordcount版本1(五)

    这个很简单哈,编程的版本很多种. 代码版本1 package zhouls.bigdata.myMapReduce.wordcount5; import java.io.IOException; im ...

  10. Solr.NET快速入门(三)【高亮显示】

    此功能会"高亮显示"匹配查询的字词(通常使用标记),包括匹配字词周围的文字片段. 要启用高亮显示,请包括HighlightingParameters QueryOptions对象, ...