• 博客园logo
  • 会员
  • 周边
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

奋斗的软件工程师

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

集合的并发修改异常问题-ConcurrentModificationException

TODO:找出集合中带张的名字,将其从集合中移除

点击查看代码
package com.itheima.javase;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * TODO:找出集合中带张的名字,将其从集合中移除
 */


public class A3 {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();


        String[] names=new String[]{"张嘉泽","张瀚文","李梦琪","王梓轩","张晨曦","赵雅婷","刘子涵","张悦然","陈炣炎","孙瑾瑜","郭宇航","张梓轩","吴思瑶","张诗琪","周心怡"};

        initList(list,names);


        traverseList(list);


        //demo1(list);
        demo2(list);


        traverseList(list);

    }

    private static void demo2(List<String> list) {
        Iterator<String> iterator = list.iterator();

        while(iterator.hasNext()){
            String name = iterator.next();

            if(name.contains("张"))
                list.remove(name);
        }

        System.out.println();

    }

    private static void demo1(List<String> list) {
        for (int i = 0; i < list.size(); i++) {
            String name = list.get(i);
            if(name.contains("张"))
                list.remove(name);
        }
    }

    private static void traverseList(List<String> list) {
        list.forEach(s -> System.out.print(s+"\t"));
        System.out.println();
    }

    private static void initList(List<String> list,String[] names) {
        for (int i = 0; i < names.length; i++) {
            list.add(names[i]);
        }


    }
}

乍一看,demo1和demo2好像都能满足要求,实际上demo1删不干净,demo2代码存在并发修改异常的问题。Exception in thread "main" java.util.ConcurrentModificationException,

demo1运行结果

张嘉泽 张瀚文 李梦琪 王梓轩 张晨曦 赵雅婷 刘子涵 张悦然 陈炣炎 孙瑾瑜 郭宇航 张梓轩 吴思瑶 张诗琪 周心怡
张瀚文 李梦琪 王梓轩 赵雅婷 刘子涵 陈炣炎 孙瑾瑜 郭宇航 吴思瑶 周心怡

demo2运行结果

张嘉泽 张瀚文 李梦琪 王梓轩 张晨曦 赵雅婷 刘子涵 张悦然 陈炣炎 孙瑾瑜 郭宇航 张梓轩 吴思瑶 张诗琪 周心怡

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911)
at java.util.ArrayList$Itr.next(ArrayList.java:861)
at com.itheima.javase.A3.demo2(A3.java:37)
at com.itheima.javase.A3.main(A3.java:26)

Process finished with exit code 1

对于demo1,使用for循环并根据索引遍历list并移除元素时,由于在循环过程中修改了list的大小(即移除了元素),可能导致某些元素被跳过或者出现下标越界异常。例如,假设正在遍历,并且决定删除索引为i的元素,list的大小减小后,原本索引为i+1的元素会移动到索引i的位置,但循环仍然会尝试访问索引i+1的元素,这可能会导致未预期的结果或错误。要修复这个问题,如下所示:

点击查看代码
  private static void demo1(List<String> list) {
        for (int i = 0; i < list.size(); i++) {
            String name = list.get(i);

            if(name.contains("张")){
                list.remove(name);
                i--;
            }
        }
    }

demo2代码存在并发修改异常的问题。具体来说,在while循环里,当iterator通过next()方法获取到一个元素后,我直接调用了list.remove(name),而不是iterator.remove()。这样做的结果是,虽然看似移除了指定元素,但实际上破坏了iterator的内部状态,因为它期望集合在遍历过程中不发生结构变化(即添加或删除元素)。所以,后续的迭代操作可能会导致ConcurrentModificationException异常。

直接调用list.remove(name)而不是iterator.remove()会导致并发修改异常(ConcurrentModificationException)。这是因为迭代器在检测到集合在其遍历期间结构发生改变时会抛出此异常。正确做法是在调用iterator.next()之后,如果满足移除条件,则调用iterator.remove()来移除当前迭代项。

要修复这个问题,应使用Iterator提供的remove()方法来移除当前迭代项,如下所示:

点击查看代码
private static void demo2(List<String> list) {
    Iterator<String> iterator = list.iterator();

    while(iterator.hasNext()){
        String name = iterator.next();
        if(name.contains("张")) {
            iterator.remove();
        }
    }

    System.out.println();
}

现在,demo2也能正确地从集合中移除包含“张”的名字了。在Java中,要安全地从ArrayList(或其他基于Iterator的集合)中移除元素,最佳做法仍然是使用迭代器提供的remove()方法,就像修正后的demo2那样实现。

总结

posted on 2024-01-31 23:59  周政然  阅读(23)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3