0%

Java: for loop vs forEach

在做leetcode的题目的时候,发现了有人用for(E e)去遍历数组的值,但是这种方法在经过我试验后却并不如for(int i = 0; i < len; i++) arr[i]快,于是就研究了一下for循环和for each的差别,顺便复习了一下java中容器的知识。所以这篇文章先理清一些关于Java中容器的知识,然后再分析for each和for循环的差别。

java中为什么会有容器的存在?

容器的主要作用还是用来保存对象,但是数组保存对象限制比较多,比如数组是固定尺寸的,添加和删除元素都会比较麻烦,所以引入容器的概念。

容器归纳

java中的容器分为collection和map两类。而Collection又分Set, List, Queue。具体可以见下图。值得提一句,Collection的父类是Iterable,而Iterable定义了forEach, iterator()的方法。

collection归纳

容器中只能存放引用数据类型,而不能存放基本数据类型。为什么呢? 在某论坛上看到有人给出这样的解释,个人觉得解释挺到位,就直接复制过来了:

首先,集合的存在就是为了方便对多个对象的操作才出现的,集合是存储对象最常用的一种方式,也就是说,集合的从有到无都是因为对象,人们发现要保存多个对象很麻烦,于是便发明了集合,集合是依赖对象而生的,所以就对基本数据类型”不感兴趣”,但是,现在基本数据类型都有了其对应的封装的对象,而且有了自动拆箱和装箱功能,基本数据类型和其对应对象之间的转换变得很方便,想把基本数据类型存入集合中,直接存就可以了,系统会自动将其装箱成封装类。然后加入集合当中

了解了一些容器相关的知识后,回到问题:for each和for 循环谁快谁慢?

这里要回顾下数组这个数据结构了。数组是用连续的内存空间来存储对象,这意味着什么?意味着可以通过寻址地址公式根据下标来随机访问(random access)元素,这个操作的时间复杂度为O(1),而链表搜寻元素要traverse the whole list。在不涉及random access的时候,for each比较快,而涉及random access的时候,就不一定了,看一些实验结果,数据量大的时候,还是for循环略快。Random access会涉及到最基本的数组和基于数组的容器ArrayList,所以碰到这两种数据结构的时候,用for循环或者for each都行。而对于LinkedList, 用for each会明显快很多。

网络参考资料

  1. Java集合不能存放基本数据类型,只存放对象的引用
  2. java容器类详解
  3. java中的容器
  4. java中的集合接口为什么不能存放基本数据类型?
  5. Iterator vs Foreach In Java