在项目的时候,报了一个错 java.util.ConcurrentModificationException
发现是list的remove方法报错,来总结一下:
例子:
public void test(){ List<String> list=new ArrayList<String>(); list.add("aaa"); list.add("bbb"); list.add("ccc"); list.stream().forEach(e->{ if ("bbb".equals(e)){ list.remove(e); } }); list.stream().forEach(System.out::println); }报错信息:
java.util.ConcurrentModificationException at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1388) at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580) at cn.ziwei.test.test.test(test.java:22)点进去,发现是这里报错:
public void forEachRemaining(Consumer<? super E> action) { // action:{“aaa","bbb","ccc"} int i, hi, mc; // hoist accesses and checks from loop ArrayList<E> lst; Object[] a; if (action == null) throw new NullPointerException(); if ((lst = list) != null && (a = lst.elementData) != null) { if ((hi = fence) < 0) { mc = lst.modCount; // modCount是修改次数,这里等于3,因为add了3次 hi = lst.size; } else mc = expectedModCount; if ((i = index) >= 0 && (index = hi) <= a.length) { for (; i < hi; ++i) { @SuppressWarnings("unchecked") E e = (E) a[i]; action.accept(e); //这里回去执行你写的逻辑,也就是if里面的判断 } // 上面的for执行完之后,就会把bbb删除,这个时候lst.modCount=4,因为remove了一次(也就是说,如果if里面的操作是add,也是会报同样的错误) // 而mc=3,显然if不成立 if (lst.modCount == mc) return; } } throw new ConcurrentModificationException(); }增强for也是如此,大家可以去看一下。不只是remove会报错,add也会,只要能够使modCount发生变化的,都会报java.util.ConcurrentModificationException
下面是增强for,抛异常的地方
例子:
public void test(){ List<String> list=new ArrayList<String>(); list.add("aaa"); list.add("bbb"); list.add("ccc"); for(String s:list){ if ("bbb".equals(s)) { list.add("ddd"); } } list.stream().forEach(System.out::println); } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }解决方法:
想到了迭代器,强大的迭代器!!
public void test(){ List<String> list=new ArrayList<String>(); list.add("aaa"); list.add("bbb"); list.add("ccc"); Iterator<String> it = list.iterator(); while (it.hasNext()){ String next = it.next(); if ("bbb".equals(next)){ it.remove(); } } list.stream().forEach(System.out::println); }不会报错,正常输出。Why?
因为:我们使用的list.remove()或者add()是使用的arraylist里面的方法。这些方法内部会增加modCount的值,而没有修改mc/expectedModCount的值,比如remove的源码:
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; }而list的迭代器的remove:
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; Itr() {} public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; // 改变expectedmodcount来使其不报错 } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } }关键:expectedModCount = modCount; // 改变expectedmodcount来使其不报错