Java中 普通for循环, 增强for循环( foreach) List中增删改查的注意事项

文章目录

俩种循环

Java中 普通for循环, 增强for循环( foreach) 俩种List的遍历方式有何异同,性能差异?

普通for循环(使用索引遍历):

java 复制代码
for (int i = 0; i < list.size(); i++) {  
    Object item = list.get(i);  
    // 处理item  
}

这是最基本的遍历方式,它使用索引来访问列表中的每一个元素。

增强for循环(也称为"foreach"循环):

java 复制代码
for (Object item : list) {  
    // 处理item  
}

这种循环在Java 5中被引入,作为对集合遍历的语法糖。在内部,它仍然使用Iterator,但语法更为简洁。很多开发者也称之为"foreach"循环,但实际上在Java中并没有名为"foreach"的关键字;这是C#中的一个关键字。在Java中,这只是增强for循环的一种常见称呼。

异同点:

普通for循环:

需要显式地通过索引来访问元素。

可以方便地访问和修改当前索引位置的元素。

对于List的随机访问操作,性能是高效的,因为ArrayList等基于数组的列表支持快速的随机访问。

增强for循环:

语法简洁,不需要关心索引。

只能访问元素,不能方便地修改元素 (除非元素是可变的对象,并且你修改了对象的内部状态)。
在内部,它使用Iterator ,所以对于不支持快速随机访问的数据结构(如LinkedList),它的性能可能更优。

性能差异:

对于ArrayList等基于数组的列表:普通for循环通常会比增强for循环稍微快一点,因为它直接通过索引访问元素,避免了Iterator的开销。但这种差异在大多数情况下是微不足道的,除非列表非常大或者这段代码是性能瓶颈。

对于LinkedList等不支持快速随机访问的列表:增强for循环可能会更有优势,因为它内部使用Iterator,这与LinkedList的迭代访问方式相匹配。

遍历

ArrayList 情况下,普通for循环遍历就是最基础的for循环,而foreach底层是使用迭代器。

增加

删除

1 根据index删除

java 复制代码
 List<String> list = new ArrayList<>(4);
        list.add("a");
        list.add("ab");
        list.add("abc");
        list.add("abcd");
java 复制代码
 //错误方式 根据下标remove  数组形式 普通for循环
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).contains("a")) {
                list.remove(i);
            }
        }

[ab, abcd]

读者可能回想,怎么不是空的list呢?不妨让我们看下remove这个方法。(这个是ArrayList 里面的实现)

java 复制代码
  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;
    }

其中

java 复制代码
 System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);

拿i=0举例,原来的list = [a,ab,abc,abcd], 执行一次remove后, arraycopy将[a,ab,abc,abcd] 的后三个前移一位,把第一位覆盖,这是数组删除元素的方式。这样一来,原list就变成[ab,abc,abcd],第二次循环的时候i=1,此时list.get(1) = abc,直接跳过了ab,所以最后没有达到我们预期的空[].

正确的做法是使用迭代器

java 复制代码
//正确方式 迭代器
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            if (iterator.next().contains("a")) {
                // 删除元素
                iterator.remove();
            }
        }

2 根据对象删除

java 复制代码
//根据对象删除
        List<String> list2 = new ArrayList<>();
        list2.add("111");
        list2.add("222");
        list2.add("222");
        list2.add("333");

正确 普通for循环

java 复制代码
//
        for (int i = 0; i <list2.size(); i++) {
            list2.remove("222");
        }

错误,增强for循环 抛异常

java 复制代码
  //
        for (String s : list2) {
            list2.remove("222");
        }

原因:

迭代器内部的每次遍历都会记录List内部的modcount当做预期值,然后在每次循环中用预期值与List的成员变量modCount作比较,但是普通list.remove调用的是List的remove,这时modcount++,但是iterator内记录的预期值并没有变化,所以会报错。

如果想要删除元素的话需要使用迭代器内部的remove方法。

修改

foreach不可以删除/修改集合元素,而for可以

foreach和for都可以修改元素(对象)里面的属性

相关推荐
qmx_0725 分钟前
HTB-Jerry(tomcat war文件、msfvenom)
java·web安全·网络安全·tomcat
为风而战33 分钟前
IIS+Ngnix+Tomcat 部署网站 用IIS实现反向代理
java·tomcat
技术无疆2 小时前
快速开发与维护:探索 AndroidAnnotations
android·java·android studio·android-studio·androidx·代码注入
架构文摘JGWZ5 小时前
Java 23 的12 个新特性!!
java·开发语言·学习
拾光师6 小时前
spring获取当前request
java·后端·spring
aPurpleBerry6 小时前
neo4j安装启动教程+对应的jdk配置
java·neo4j
我是苏苏6 小时前
Web开发:ABP框架2——入门级别的增删改查Demo
java·开发语言
xujinwei_gingko7 小时前
Spring IOC容器Bean对象管理-Java Config方式
java·spring
2301_789985947 小时前
Java语言程序设计基础篇_编程练习题*18.29(某个目录下的文件数目)
java·开发语言·学习
IT学长编程7 小时前
计算机毕业设计 教师科研信息管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·毕业设计·springboot·毕业论文·计算机毕业设计选题·计算机毕业设计开题报告·教师科研管理系统