java.util.ConcurrentModificationException

来源:互联网 发布:我的世界mac版整合包 编辑:程序博客网 时间:2024/06/05 18:43

最近在项目过程中,遇到一个需要在set集合中删除满足条件元素的需求,当时没有多想,直接实用Iterator遍历Set,然后,调用了Set的remove(Object o)方法将对象删除,结果,意外的报了一个异常:java.util.ConcurrentModificationException。经过分析,引起该异常的原因正是因为执行了Set的remove(Object o)方法。下面贴出一段测试代码:

public class Test {    public static void main(String[] args) {        Set<String> set = new HashSet<String>();        set.add("one");        set.add("two");        set.add("three");        Iterator<String> it = set.iterator();        String str = null;        while (it.hasNext()) {            str = it.next();            set.remove(str);        }        System.out.println(set);    }}

执行结果:

Exception in thread "main" java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)at java.util.HashMap$KeyIterator.next(HashMap.java:828)at com.action.ajax.Test.main(Test.java:16)

查看JDK源码发现在迭代Iterator时建立了一个List的内部类Itr。
源码:

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

在new Itr()时有一个关键性的操作

int expectedModCount = modCount;

我们先看一下当List调用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 void fastRemove(int index) {    modCount++;    int numMoved = size – index1;    if (numMoved > 0)    System.arraycopy(elementData, index+1, elementData, index,    numMoved);    elementData[--size] = null;}

看到这里大家注意一下modCount这个变量,当执行remove方法时此变量执行了modCount++操作。

再看一下 iterator.next()操作

public E next() {    checkForComodification();    try {        E next = get(cursor);        lastRet = cursor++;        return next;    } catch (IndexOutOfBoundsException e) {        checkForComodification();        throw new NoSuchElementException();    }}final void checkForComodification() {    if (modCount != expectedModCount)        throw new ConcurrentModificationException();}

看到这儿相信大家已经应该明白了为什么会出现在这个异常了。当迭代器Iterator创建时,将定义一个变量expectedModCount,并且把modCount的值赋给它;在List执行remove()时,modCount++;在Iterator执行next()迭代下一个元素时,做了一个if判断比较expectedModCount和modCount值时候相同,如果不同直接抛出ConcurrentModificationException异常:

在这里提供给大家两种解决方案:
方案一:在集合remove之前,迭代器也remove:

public class Test {        public static void main(String[] args) {            Set<String> set = new HashSet<String>();            set.add("one");            set.add("two");            set.add("three");            Iterator<String> it = set.iterator();            String str = null;            while (it.hasNext()) {                str = it.next();                it.remove();                set.remove(str);            }            System.out.println(set);        }    }

方案二:新建一个list,把需要迭代删除的元素保存进list在set遍历完成后调用removeAll(Object o)删除即可:

public class Test {    public static void main(String[] args) {        Set<String> set = new HashSet<String>();        set.add("one");        set.add("two");        set.add("three");        Iterator<String> it = set.iterator();        String str = null;        List<String> list = new ArrayList<String>();        while (it.hasNext()) {            str = it.next();            list.add(str);        }        set.removeAll(list);        System.out.println(set);    }}
   此外,其他如List等集合使用Iterator迭代删除时也会出现这样的异常,大家采用类似的解决方法即可。   因为时间问题,对本异常没有进行过深的分析,暂时也只想到这两种解决方案,不足之处希望大家补充,后续会抽时间深入研究并完善此文。
0 0
原创粉丝点击