java.util.ConcurrentModificationException

最近在项目过程中,遇到一个需要在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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值