IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 高薪程序员&面试题精讲系列18之for和foreach的区别、原理,哪个效率更高? -> 正文阅读

[Java知识库]高薪程序员&面试题精讲系列18之for和foreach的区别、原理,哪个效率更高?

一. 面试题及剖析

1. 今日面试题

我们在刚开始学习Java基础知识的时候,很早就接触到了关于循环的内容,在面试时,面试官在这个地方也可能会问到一些面试题,比如:

for和foreach有什么区别?

for与foreach循环的原理是什么样的?

两者哪个效率更高?

2. 题目剖析

上面这个题目主要是考察我们对Java中循环的操作和理解,这道题目本身没有太难的地方,题目的答案以记忆为主,没有太多需要理解的地方。

二. 参考答案

1. for与foreach的区别

1.1 语法不同

常规的for循环语法如下:

for(statement 1; statement 2; statement 3) {
    //要执行的循环语句
}

增强型foreach是 Java 提供的一种语法糖,主要用来对数组或者集合进行遍历,其语法格式如下:

for(元素类型type 元素变量value : 遍历的集合对象obj) { 
  //要执行的循环语句
}

1.2 使用场景不同

  • 普通for循环可以在各类型的循环操作中使用,如果我们想遍历集合时还能对元素进行修改,就要使用for循环;
  • foreach是对for循环的简化,任何foreach循环都能改写成for循环,但是反之则不行,即foreach并不能完全替代for循环。foreach循环适用于对数组或实现了iterator接口的集合类进行遍历操作。
  • foreach适用于循环次数未知,或者计算循环次数比较麻烦情况下,但是一些更复杂的循环还是for循环效率更高。

1.3 执行原理不同

  • 普通for循环在遍历集合、数组时会使用下标来定位集合中的元素;
  • for循环中,我们可以选择从前往后遍历,也可以从后往前遍历;
  • foreach只能从前往后遍历,而且每一个元素都会遍历一次;
  • foreach基于数据类型来进行集合遍历;
  • foreach在遍历Array数组时,会把foreach循环转为普通的for循环;foreach在遍历List等集合时,会使用Iterator迭代器进行循环遍历;
  • 在用foreach循环遍历List集合时,虽然其循环遍历内部基于Iterator,但它不能像Iterator一样可以人为控制,比如不能调用iterator.remove()方法。foreach也不能使用下标来访问每个元素,所以不能利用foreach来改变集合中的元素,如增加元素、修改元素、删除元素,否则会抛出ConcurrentModificationException异常。

1.4 循环执行效果不同

  • 如果数组中的元素是基本数据类型,则在foreach循环中修改某个元素时对原数组中的值是没有影响的,因为foreach是对原数组中的元素拷贝一份之后,再对拷贝得到的元素进行操作;
  • 如果原数组中的对象是引用类型,则在foreach中可以通过复制来的引用变量对元素对象的内容进行修改,但是String不可以,因为String类型的对象一旦初始化后是不可以修改的。

1.5 性能不同

foreach语句是Java5中新增的循环功能,在遍历数组、集合时性能比一般的for循环要高一些

1.6 各自优缺点不同

  • 普通for循环语法相对来说稍微复杂点;
  • foreach虽然能遍历数组或者集合,但是只能用来遍历,无法在遍历的过程中对数组或者集合进行修改,而for循环可以在遍历的过程中对源数组或者集合进行修改;
  • foreach循环只能从头到尾的遍历数组或集合,而不能只遍历部分;
  • 因为Map没有实现Iterable接口,我们不能直接使用增强for来遍历。

三. foreach遍历操作底层原理

为了加深各位对foreach遍历操作的理解,壹哥 再深入讲解一下foreach遍历操作的底层原理。

我们可以先编写一个Java类,内部定义一个数组与一个集合,然后利用foreach循环分别对其进行遍历。

   public static void main(String[] args) {
        //foreach对数组的遍历底层原理
        String[] names = {"syc", "yyg", "yiyige"};
        //使用foreach循环遍历数组
        for (Object name : names) {
            System.out.println("name=" + name);
        }

        //foreach对List集合循环遍历的底层原理
        List<String> cities = new ArrayList<>();
        cities.add("beijing");
        cities.add("shanghai");
        cities.add("guangzhou");
        cities.add("shenzhen");

        for (String city : cities) {
            System.out.println("city=" + city);
        }
    }

上面定义的Java类编写之后,我们先编译生成对应的Java字节码,然后使用JAD反编译工具,对该字节码进行反编译,可以看到反编译后的效果如下图所示:

最终得出结论如下:

当利用foreach这个语法糖遍历一个Array数组时,其实会把foreach循环转为普通的for循环。而foreach在遍历List等集合时,是使用的Iterator迭代器。

四. 实验代码

接下来 壹哥 设计几个代码案例,分别测试for与foreach循环,在遍历时是否可以对集合元素进行增、删、改操作。

1. 普通for循环添加或移除元素

我先测试普通for循环遍历时对元素进行修改操作。

   public static void main(String[] args) {
        //测试for与foreach遍历时的增删改操作
       
        List<String> cities = new ArrayList<>();
        cities.add("北京");
        cities.add("上海");
        cities.add("广州");
        cities.add("深圳");

        System.out.println("集合遍历之前:" + cities);
        //使用for循环遍历数组
        for (int i = 0; i < cities.size(); i++) {
            cities.remove("上海");
        }
        System.out.println("集合遍历之后:" + cities);

    }

执行结果如下:

2. foreach循环添加或移除元素

接着我再测试foreach循环遍历时对元素进行修改操作。

    public static void main(String[] args) {
        //测试for与foreach遍历时的增删改操作
        List<String> cities = new ArrayList<>();
        cities.add("北京");
        cities.add("上海");
        cities.add("广州");
        cities.add("深圳");

        System.out.println("集合遍历之前:" + cities);

        //使用foreach循环遍历数组
        for (String s : cities) {
            cities.remove("上海");
        }

        System.out.println("集合遍历之后:" + cities);
    }

执行结果如下:

从上面的代码执行结果可以看出,foreach循环遍历时,如果对元素进行添加、修改、删除操作,会抛出ConcurrenModificationException异常。

3. ConcurrentModificationException异常原因分析

这时候你可能会很好奇,为什么普通的for循环遍历时就可以对元素进行添加、删除等操作,而在foreach循环遍历时就会出现ConcurrentModificationException异常呢?

别急,壹哥 给各位分析一下。

foreach遍历时进行元素添加、删除时,之所以会出现ConcurrentModificationException异常,这是因为foreach循环对List等集合遍历时,内部是利用Iterator迭代器进行遍历的。而当迭代器运行的时候,会在当前线程 A 中,单独的创建一个线程 B,A 线程负责继续迭代,B 线程负责元素删除。但是 B 线程每删除一个元素,都会去检查 A 线程中的元素与B线程中的元素还是否相同,如果不相同就会产生并发操作异常原理如下图所示:

4. 问题解决

这时候可能会有小伙伴提出新的问题,如果我们非要在foreach循环中删除集合元素,可不可以呢?既然有这样的需求,那么 壹哥 就尽量想办法满足小伙伴的需求啦~(@^_^@)~

我们知道,在上面代码中,删除方法是用的Collection(ArrayList 的父类) 集合中的 remove()方法,但该方法只能从集合中删除元素,而不能把迭代器中的元素也删除了,所以我们可以使用 iterator 迭代器中的remove()方法来进行删除集合元素,另外foreach循环也要更改为while循环。代码如下:

    public static void main(String[] args) {
        //测试for与foreach遍历时的增删改操作
        List<String> cities = new ArrayList<>();
        cities.add("北京");
        cities.add("上海");
        cities.add("广州");
        cities.add("深圳");

        System.out.println("集合遍历之前:" + cities);

        Iterator<String> iterator = cities.iterator();
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            if ("上海".equals(obj)) {
                //list.remove(obj);//如果你用 集合 方法,那么还是会报错
                iterator.remove();//这里是用 迭代器的 remove() 方法<br>
            }
        }

        System.out.println("集合遍历之后:" + cities);
    }

执行结果如下:

五. 结论

这样 壹哥 就为各位分析梳理了for与foreach循环的区别,主要是从以下方面进行分析的:

语法不通;

使用场景不同;

执行原理不同;

循环执行效果不同;

性能不同;

各自优缺点不同

另外我们还要弄清楚foreach底层操作的相关原理,尤其是foreach操作时为什么不能进行元素的修改操作,清楚ConcurrentModificationException异常的产生原因。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-18 11:04:23  更:2021-11-18 11:04:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:45:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码