Java 删除集合中的元素异常问题之ConcurrentModificationException

今天在做代码开始时,遇到一个这样的场景:

    /**
     * 过滤掉维度数据中不需要传递的字段
     *
     * @param dataJsonObj {"is_sale":0,"sku_desc":"小米12S Ultra 骁龙8+旗舰处理器 徕卡光学镜头 2K超视感屏 120Hz高刷 67W快充 12GB+256GB 经典黑 5G手机","tm_id":5,"create_time":"2021-12-14 00:00:00","price":6499,"sku_default_img":"http://47.93.148.192:8080/group1/M00/00/01/rBHu8l-rfvmAIpgZAAIvrX6L9fo612.jpg","weight":1.00,"sku_name":"小米12S Ultra 骁龙8+旗舰处理器 徕卡光学镜头 2K超视感屏 120Hz高刷 67W快充 12GB+256GB 经典黑 5G手机666","id":3,"spu_id":1,"category3_id":61}
     * @param sinkColumns id,spu_id,price,sku_name,sku_desc,weight,tm_id,category3_id,sku_default_img,is_sale,create_time
     */
    private static void deleteNotNeedColumns(JSONObject dataJsonObj, String sinkColumns) {

        List<String> sinkColumnsList = Arrays.asList(sinkColumns.split(","));

        Set<Map.Entry<String, Object>> entrySet = dataJsonObj.entrySet();

        // 不能在遍历集合的时候,去删除集合中的元素
        for (Map.Entry<String, Object> entry : entrySet) {
            if (sinkColumnsList.contains(entry.getKey())) {
                entrySet.remove(entry);
            }
        }
    }

相信大家对于这种实现思路都可以想到,但是当我们以为我们很聪明的时候,问题就出现了:
在这里插入图片描述
后面查找到了原因**(还是自己Java基础不好)**:
在Java中,遍历集合(如ArrayListHashSet等)时直接删除集合中的元素可能会导致ConcurrentModificationException异常。这是因为大多数Java集合框架中的集合类(除了ConcurrentHashMap等并发集合)并不是线程安全的,也不是设计为在迭代过程中进行修改的。

这里有几个关键点解释为什么不能在遍历过程中删除元素:

  1. 内部状态不一致:集合类通常维护一个内部状态(如modCount),用于检测集合在迭代过程中是否被修改。如果在迭代过程中修改了集合(如添加或删除元素),modCount会增加,而迭代器检测到modCount变化后会抛出ConcurrentModificationException

  2. 迭代器失效:迭代器在创建时依赖于集合的当前状态。如果在迭代过程中修改了集合,迭代器可能会失效,因为它依赖的集合状态已经改变。这可能导致迭代器返回错误的结果或抛出异常。

  3. 线程安全问题:如果在多线程环境中,多个线程同时修改集合,而没有适当的同步机制,那么集合的状态将变得不可预测,这可能导致ConcurrentModificationException或更严重的并发问题。

如何在遍历过程中安全地删除元素?

尽管直接在遍历过程中删除元素是不安全的,但有几种方法可以在遍历集合时安全地删除元素:

  1. 使用Iteratorremove方法
    使用集合的iterator()方法获取迭代器,并在遍历过程中使用迭代器的remove()方法来删除元素。这是安全的方法,因为它会正确地更新迭代器的内部状态。

    List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
        String element = iterator.next();
        if (element.equals("b")) {
            iterator.remove();
        }
    }
    
  2. 使用Java 8的removeIf方法
    如果你使用的是Java 8或更高版本,可以使用Collection接口的removeIf方法,它接受一个Predicate作为参数,并安全地从集合中删除满足条件的元素。

    List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
    list.removeIf(element -> element.equals("b"));
    
  3. 使用for-each循环结合Iterator(不推荐,但可行):
    虽然直接在for-each循环中删除元素会导致异常,但你可以结合使用Iteratorfor-each风格的循环中安全删除元素(实际上这种写法不常见,直接使用Iterator的循环更清晰)。

  4. 使用临时集合收集要删除的元素
    先遍历集合,将要删除的元素收集到一个临时集合中,然后再遍历这个临时集合并从原集合中删除这些元素。这种方法虽然可行,但效率较低,且不如使用IteratorremoveIf方法直接。

总的来说,使用Iteratorremove方法或Java 8的removeIf方法是遍历集合时安全删除元素的最佳实践。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嗨皮一会吧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值