• Java遍历集合元素并修改


    结论:fori循环可以修改、删除、添加,但是要注意的是下标还是元素;增强for循环内,可以修改,不可以删除、添加。想要删除、添加,使用集合迭代器的删除、添加方法。

    对List和Set的遍历,有四种方式,下面以ArrayList为例进行说明。

    1.1 fori循环
    使用普通for循环的遍历方式效率最高,尽量将循环无关的代码放置在集合外执行。

    代码如下:

    for (int i = 0; i < list.size(); i++) {
        System.out.println(i);
    }
    
    • 1
    • 2
    • 3

    如果要在普通for循环里对集合元素进行删除操作,可能会出现问题:

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(2);
        list.add(4);
        list.add(5);
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i) == 2) {
                list.remove(i);
            }
        }
        System.out.println(list);
    }
    //运行结果如下:
    
    //[1, 2, 4, 5]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    结果说明:

    集合中有两个值为2的元素,但是在代码执行之后,值为2的元素并没有完全移除。

    在第一次删除后,集合发生了改变,删除位置之后的所有元素都向前挪动了一个位置,删除位置上的元素由下一位置上的元素替代。

    在下次遍历时,从删除位置后开始判断,跳过了删除位置上的元素,从而导致最后打印的结果和预期的不一致。

    改进的办法是在删除之后设置索引减1,重新判断删除位置上的元素。

    1.2 增强for循环
    进一步精简了遍历的代码,底层使用迭代器。

    代码如下:

    for (Integer i : list) {
        System.out.println(i);
    }
    
    • 1
    • 2
    • 3

    如果在增强for循环里删除或者添加集合元素,那么一定会报异常:

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(2);
        list.add(4);
        list.add(5);
        for (Integer i : list) {
            if (i == 2) {
                list.remove(i);
            }
        }
        System.out.println(list);
    }
    //运行结果如下:
    
    //java.util.ConcurrentModificationException
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    结果说明:

    抛出ConcurrentModificationException异常是由快速失败(fail-fast)机制引起的,该机制是为了避免在遍历集合时,对集合的结构进行修改。

    快速失败机制使用modCount记录集合的修改次数,在删除时除了删除对应元素外,还会更新modCount。

    增强for循环本质上是使用迭代器进行遍历,迭代器在初始化时会使用expectedModCount记录当时的modCount,遍历时会检查expectedModCount是否和modCount相同,如果不同就会抛出ConcurrentModificationException异常。

    1.3 使用迭代器
    代码如下:

    Iterator<Integer> iterator = list.iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }
    
    • 1
    • 2
    • 3
    • 4

    如果在迭代器中使用集合提供的删除或添加方法,同样会报错:

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(2);
        list.add(4);
        list.add(5);
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            if (iterator.next() == 2) {
                list.add(6);
            }
        }
        System.out.println(list);
    }
    //运行结果如下:
    
    //java.util.ConcurrentModificationException
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    结果说明:

    这里抛出异常的原因和增强for循环一样,同样是因为快速失败机制。

    解决办法是在迭代器中删除或添加元素时,使用迭代器提供的删除或添加方法,不要使用集合提供的删除或添加方法。

    需要注意的是,普通迭代器中只提供了删除方法,在集合迭代器中还提供了添加和修改方法。

    1.4 使用集合迭代器
    代码如下:

    ListIterator<Integer> iterator = list.listIterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }
    
    • 1
    • 2
    • 3
    • 4

    在迭代器中使用迭代器提供的删除或添加方法:

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(2);
        list.add(4);
        list.add(5);
        ListIterator<Integer> iterator = list.listIterator();
        while (iterator.hasNext()) {
            if (iterator.next() == 2) {
                iterator.remove();
            }
        }
        System.out.println(list);
    }
    //运行结果如下:
    
    //[1, 4, 5]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    结果说明:

    迭代器提供的方法同时维护了modCount和expectedModCount,所以不会产生快速失败。

    1.5 使用forEach方法
    forEach方法是JDK1.8新增的方法,需要配合Lambda表达式使用,代码如下:

    list.forEach(i -> System.out.println(i));
    
    • 1

    使用forEach方法遍历:

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(2);
        list.add(4);
        list.add(5);
        list.forEach(i -> {
            if (i == 2) {
                list.remove(i);
            }
        });
        System.out.println(list);
    }
    //运行结果如下:
    
    //java.util.ConcurrentModificationException
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    结果说明:

    这里抛出异常的原因也是因为快速失败机制。

  • 相关阅读:
    C++入门03——程序流程结构
    下载JDK8 JVM源码
    [pytorch] 2D + 3D ResNet代码实现, 改写
    2021年03月 Scratch(二级)真题解析#中国电子学会#全国青少年软件编程等级考试
    基于Vue+ELement搭建登陆注册页面实现后端交互
    玄机科技闪耀中国国际动漫节,携手百度共绘 AI 国漫新篇章
    猿创征文 | 如何使用原生AJAX请求数据
    spring-aop-execution表达式
    matlab 计算数组中所有值的均值
    网络安全清单:每个团队在远程工作时都需要了解的内容
  • 原文地址:https://blog.csdn.net/qq_46249770/article/details/128013862