java.util.ConcurrentModificationException异常

今天在做牛客的社区项目时,因为自己用错变量而弹出了一个异常,以前面见过,就记录一下,还是学到了新东西,就是java.util.ConcurrentModificationException这个异常

是在增强for循环中发现的,在开发社区评论功能的时候有如下一段代码

List<Comment> replyList = commentService.findCommentsByEntity(
                        ENTITY_TYPE_COMMENT, comment.getId(), 0, Integer.MAX_VALUE);
                //回复的VO列表
                List<Map<String, Object>> replyVoList = new ArrayList<>();
                if (replyList != null) {
                    for (Comment reply : replyList) {
                        Map<String, Object> replyVo = new HashMap<>();
                        //回复
                        replyVo.put("reply", reply);
                        //作者
                        replyVo.put("user", userService.findUserById(reply.getUserId()));
                        //回复的目标
                        User taget = reply.getTargetId() == 0 ? null : userService.findUserById(reply.getTargetId());
                        replyVo.put("target", taget);
                        replyVoList.add(replyVo);
                    }
                }

然后我自己在add(replyVo)时代码写错了,写成了

replyList.add(replyVo);

这下就报错了,出现了文章开头说的的异常,把出错的代码提炼出来如下所示:

            List<Comment> replyList = commentService.findCommentsByEntity(
                        ENTITY_TYPE_COMMENT, comment.getId(), 0, Integer.MAX_VALUE);
            for (Comment reply : replyList) {
                        Map<String, Object> replyVo = new HashMap<>();
                        //回复
                        replyVo.put("reply", reply);
                        //作者
                        replyVo.put("user", userService.findUserById(reply.getUserId()));
                        //回复的目标
                        User taget = reply.getTargetId() == 0 ? null : userService.findUserById(reply.getTargetId());
                        replyVo.put("target", taget);
                        replyList.add(replyVo);
                    }

就是以上代码,在我遍历完一次后再接着遍历的时候就抛出来的异常;然后就去网搜了下,大概意思就是咱们的ArrayList会维护一个modcount,咱ArrayList中的迭代器也会维护一个自己的count,当发现这两个count不一样的时候就会抛出这个异常。

下面我们来看看源码,看看到低在哪儿抛的异常

首先看看ArrayList的源码:(只展示一下主要部分喽)

    public abstract class AbstractList<E> extends AbstractCollection<E> implements        List<E> {
        protected transient int modCount = 0;
    }

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
        public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;
            return true;
        }

        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;
        }

        private void ensureCapacityInternal(int minCapacity) {
            ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
        }

        private void ensureExplicitCapacity(int minCapacity) {
            modCount++;

            // overflow-conscious code
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
    }

可以看到咱们ArrayList的增加和删除方法都会对modcount进行修改,然后来看看迭代器的源码

private class Itr implements Iterator<E> {
        
        int expectedModCount = modCount;
        

        @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];
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

可以看到迭代器在每次调用next方法的时候都会检查modCount和expectedModCount是否相等,不想等就会抛出异常了。

好,现在再来回顾一下刚刚错误的代码,增强for循环的底层是迭代器遍历,所以在对replyList的增强for循环中,当我们第一次执行到replyList.add(replyVo)的时候我们replyList的modCount就会++,但是这个时候迭代器中的expectedModCount还是原来的值,所以在进行增强for循环执行第二次的时候,会执行迭代器的next()方法,这个时候一检查就发现replyList迭代器的expectedModCount和replyList的modCount不相等,所以这个时候就会抛出异常了

解决方案的话可以参考这篇这篇博客java.util.ConcurrentModificationException详解 - 简书

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值