首页 > 编程语言 >Java在for循环中修改集合

Java在for循环中修改集合

时间:2024-10-15 17:21:24浏览次数:1  
标签:遍历 Java iterator list System 修改 add 集合 out

前天看到一篇文章什么?for循环也会出问题?,里面涉及到在for循环中修改集合,想起来自己刚入行的时候就碰到过类似的问题,于是复现了一下文章中的问题,并试验了其它在循环中修改集合的方法。

底层原理参考什么?for循环也会出问题?这篇文章的分析

1. 在fori中修改集合

  • 在fori中修改集合,不会抛出异常
  • 在fori中移除元素,部分元素可能会被跳过,无法被遍历到
  • 在fori中添加元素,遍历时元素不会被跳过,但如果添加的元素恰好满足添加元素的条件,可能导致无限循环

代码如下:

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

public class TestFor {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        System.out.println("*****遍历时移除元素*****");
        for (int index = 0; index < list.size(); index++) {
            Integer num = list.get(index);
            System.out.println("当前遍历:" + num);
            if (num % 2 == 0) {
                list.remove(num);
                System.out.println("移除:" + num);
            }
        }
        list.forEach(o -> System.out.print(o + "\t"));

        System.out.println();
        list.clear();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        System.out.println("*****遍历时添加元素*****");
        for (int index = 0; index < list.size(); index++) {
            Integer num = list.get(index);
            System.out.println("当前遍历:" + num);
            if (num % 2 == 0) {
                int addNum = 101 + num; // 让添加进去的addNum为奇数,防止后面都是偶数,导致无限循环
                list.add(addNum);
                System.out.println("添加:" + addNum);
            }
        }
        list.forEach(o -> System.out.print(o + "\t"));
    }
}
 
 

 

运行结果:

*****遍历时移除元素*****
当前遍历:1
当前遍历:2
移除:2
当前遍历:4
移除:4
1    3    5
*****遍历时添加元素*****
当前遍历:1
当前遍历:2
添加:103
当前遍历:3
当前遍历:4
添加:105
当前遍历:5
当前遍历:103
当前遍历:105
1    2    3    4    5    103    105
 
 

 

2. 在迭代器iterator中修改集合

  • 在iterator中通过iterator修改集合(remove),不会抛出异常
  • 在iterator中移除元素,元素不会被跳过,但iterator.remove()前,必须先执行iterator.next(),将next element的索引+1,否则会出现IllegalStateException
  • 使用iterator遍历元素时,跳过iterator直接去修改list,只要修改后再次执行iterator.next(),都会出现ConcurrentModificationException
  • 使用iterator遍历元素时,即便在最后一次遍历中(此时iterator.hasNext()为false)才执行list.add()或list.remove(),也会导致iterator.hasNext()从false变为true

代码如下:

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

public class TestFor {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        System.out.println("*****遍历时移除元素*****");
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            // iterator.remove()前,必须先执行iterator.next(),将next element的索引+1,否则会出现IllegalStateException
            Integer num = iterator.next();
            System.out.println("当前遍历:" + num);
            if (num % 2 == 0) {
                iterator.remove();
                System.out.println("移除:" + num);
            }
        }
        list.forEach(o -> System.out.print(o + "\t"));

        System.out.println();
        list.clear();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        System.out.println("*****遍历时修改list,修改后不执行iterator.next()*****");
        iterator = list.iterator();
        while (iterator.hasNext()) {
            Integer num = iterator.next();
            System.out.println("当前遍历:" + num);
            if (num == 5) {
                // list.add()、list.remove()都会导致iterator.hasNext()从false变为true
                Collections.sort(list);
                System.out.println("===>排序");
            }
        }
        list.forEach(o -> System.out.print(o + "\t"));
        System.out.println();
        list.clear();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        System.out.println("*****遍历时修改list,修改后执行iterator.next()*****");
        iterator = list.iterator();
        while (iterator.hasNext()) {
            Integer num = iterator.next();
            System.out.println("当前遍历:" + num);
            if (num == 3) {
                Collections.sort(list);
                System.out.println("===>排序");
            }
        }
        list.forEach(o -> System.out.print(o + "\t"));
    }
}
 
 

 

运行结果:

*****遍历时移除元素*****
当前遍历:1
当前遍历:2
移除:2
当前遍历:3
当前遍历:4
移除:4
当前遍历:5
1    3    5
*****遍历时修改list,修改后不执行iterator.next()*****
当前遍历:1
当前遍历:2
当前遍历:3
当前遍历:4
当前遍历:5
===>排序
1    2    3    4    5
*****遍历时修改list,修改后执行iterator.next()*****
当前遍历:1
当前遍历:2
当前遍历:3
===>排序
Exception in thread "main" java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
    at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
    at http.TestFor.main(TestFor.java:56)
 
 

 

3. 在foreach中修改集合

查看编译后的.class后可知,foreach只是迭代器iterator的语法糖,编译后也是用iterator遍历,所以跟在迭代器iterator中修改集合一样

  • 在foreach中没有提供修改list的接口,在非最后一次遍历中修改list会出现ConcurrentModificationException
  • 使用foreach遍历元素时,只在最后一次遍历中修改list(不执行list.add()或list.remove(),而是其它操作比如排序),不会出现ConcurrentModificationException
  • 使用foreach遍历元素时,即便在最后一次遍历中才执行list.add()或list.remove(),也会出现ConcurrentModificationException

代码如下:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TestFor {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        System.out.println("*****遍历时修改list,最后一次遍历时修改(不涉及list.add()、list.remove())*****");
        for (Integer num : list) {
            System.out.println("当前遍历:" + num);
            if (num == 5) {
                // 查看编译后的.class后可知,foreach只是iterator的语法糖,编译后也是用iterator遍历
                // 如果在最后一次遍历中执行list.add()或list.remove(),会导致ConcurrentModificationException
                Collections.sort(list);
                System.out.println("===>排序");
            }
        }
        list.forEach(o -> System.out.print(o + "\t"));

        System.out.println();
        System.out.println("*****遍历时修改list,在非最后一次遍历时修改*****");
        for (Integer num : list) {
            System.out.println("当前遍历:" + num);
            if (num == 3) {
                Collections.sort(list);
                System.out.println("===>排序");
            }
        }
        list.forEach(o -> System.out.print(o + "\t"));
    }
}
 
 

 

运行结果:

*****遍历时修改list,最后一次遍历时修改(不涉及list.add()、list.remove())*****
当前遍历:1
当前遍历:2
当前遍历:3
当前遍历:4
当前遍历:5
===>排序
1    2    3    4    5
*****遍历时修改list,在非最后一次遍历时修改*****
当前遍历:1
当前遍历:2
当前遍历:3
===>排序
Exception in thread "main" java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
    at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
    at http.TestFor.main(TestFor.java:27)
 
 

 

总结

  • 尽量不要在遍历中修改集合本身(修改集合中的元素的属性没问题),除非你能明确知道该操作导致的后果。
  • 如果需要在循环中移除元素,可以使用迭代器iterator。

标签:遍历,Java,iterator,list,System,修改,add,集合,out
From: https://www.cnblogs.com/pqdl4312/p/18468010

相关文章

  • 集合Collection接口中的成员方法
    一、Collection集合的介绍:1.Collection是一个接口,List,Set是继承Collection接口的子接口2.当我们使用Collection的方法的时候,由于是一个接口不能直接new对象,可以通过其具体实现的子类来进行调用二、Collection的基本方法(6)1.booleanadd(Ee),可以传任意一个类型的元素进去2......
  • java计算机毕业设计智能点餐推荐系统(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着科技的飞速发展,人们的生活节奏日益加快,对餐饮服务的需求也愈发多样化和个性化。传统的点餐方式往往依赖于纸质菜单或简单的电子菜单,难以满足现代......
  • Java在for循环中修改集合
    在Java中,ifPresent是一个用于Optional类型的方法,用于检查Optional对象中是否存在值并执行相应的操作。ifPresent方法接受一个Consumer函数式接口作为参数,如果Optional对象中包含值,则将该值传递给Consumer接口的实现方法。以下是ifPresent方法的使用示例:importj......
  • 软件开发----Java基础每日刷题(转载于牛客)
    1.        A 是抽象父类或接口, B , C 派生自 A ,或实现 A ,现在 Java 源代码中有如下声明:1. A a0=new A();2. A a1=new B();3. A a2=new C();问以下哪个说法是正确的?()A        第1行不能通过编译B        第1、2行能通......
  • Java 时间格式转换详解
    在Java开发中,时间和日期的处理是非常常见的需求。无论是用户输入的时间数据,还是系统生成的时间戳,我们经常需要对其进行格式化或解析。本文将详细介绍如何在Java中进行时间格式的转换,并分别介绍两种主要的方法:SimpleDateFormat(适用于Java8之前)和 java.time(适用于Java8......
  • JavaSE JAVA基础总结(一) 我的学习笔记
    JavaSEJAVA基础总结(一)一、Java基础语法1.数据类型2.运算符3.选择结构4.循环结构5.数组6.方法7.递归二、面向对象1.面向对象编程(1)为什么要学习面向对象(2)面向过程与面向对象区别(3)对象(4)类(5)成员变量与局部变量的区别(6)构造器(7)this的关键字(8)标准JavaBean(9)静态关键字:static......
  • java计算机毕业设计基于springboot的居家健身系统的设计与实现(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着现代生活节奏的加快,人们越来越注重健康与身体锻炼。然而,繁忙的工作和生活压力使得很多人难以抽出时间前往健身房进行锻炼。居家健身作为一种灵活......
  • java计算机毕业设计在线教育平台的设计与实现(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展和全球信息化趋势的加强,教育领域正经历着前所未有的变革。在线教育平台作为互联网+教育的重要产物,已经逐渐成为人们获取知......
  • java计算机毕业设计智慧迎新系统(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和高校管理水平的不断提升,智慧迎新系统逐渐成为各大高校优化新生入学流程、提升服务质量的重要手段。传统迎新工作存在流程繁......
  • 二Java环境
    Java环境笔记Java开发工具包(JDK)组成:包含Java运行环境(JRE)开发工具,如编译器(javac)、调试器等Java运行环境(JRE)组成:包含Java虚拟机(JVM)核心类库,提供Java程序运行所需的基础功能Java虚拟机(JVM)作用:保证Java语言的跨平台性,即“一次编写,到处运行”Java平台......