最近跟foreach算是很有缘分吧,前一天同事跟我聊一个自己在网上看到的“ foreach使用过多会有性能问题,建议使用for i++来做遍历? ”我当时一听就纳闷了,以前的时候看到文章说JVM对foreach语法糖是有做优化的,在很多博客也是推荐使用foreach的,为什么突然会有这么个说法呢,今天躺床上看到个博客 Java 性能优化的五大技巧 的第五点钟第2条中说“避免使用iterator()”,我决定试试究竟!
执行时间(1000*1000数据量)
ArrayLIst的遍历时间对比( 实验结果证明foreach要比for++要差那么些,但是非常接近 )
long start = System.currentTimeMillis(); for (int i = 0; i < list.size(); i ++) { String s = list.get(i); } System.out.println("arrayList for i++ on 1000*1000 records time waste: " + (System.currentTimeMillis() - start)); start = System.currentTimeMillis(); for (String s : list) { // } System.out.println("arrayList foreach on 1000*1000 records time waste: " + (System.currentTimeMillis() - start)); |
执行结果:
第1次:
arrayList for i++ on 1000*1000 records time waste: 0
arrayList foreach on 1000*1000 records time waste: 16
第2次:
arrayList for i++ on 1000*1000 records time waste: 0
arrayList foreach on 1000*1000 records time waste: 0
第3次:
arrayList for i++ on 1000*1000 records time waste: 0
arrayList foreach on 1000*1000 records time waste: 0
LinkedLIst的遍历时间对比( 实验结果证明foreach要比for++好N多数量级倍,N具体多少取决于数据量 )
for (int i = 0; i < list.size(); i ++) { String s = list.get(i); } System.out.println("LinkedList for i++ on 1000*1000 records time waste: " + (System.currentTimeMillis() - start)); start = System.currentTimeMillis(); for (String s : list) { // } System.out.println("LinkedList foreach on 1000*1000 records time waste: " + (System.currentTimeMillis() - start)); |
实验结果
第一次:
LinkedList for i++ on 1000*1000 records time waste: 41224
LinkedList foreach on 1000*1000 records time waste: 11
第二次:
LinkedList for i++ on 1000*1000 records time waste: 43914
LinkedList foreach on 1000*1000 records time waste: 11
第三次:
LinkedList for i++ on 1000*1000 records time waste: 57320
LinkedList foreach on 1000*1000 records time waste: 16
Array的遍历时间对比( 实验结果证明foreach要比for++要差那么些,但是非常接近,与ArrayList竟然那么相似 )
String[] array = (String[])list.toArray(new String[]{}); long start = System.currentTimeMillis(); for (int i = 0; i < array.length; i ++) { String s = array[i]; } System.out.println("Array for i++ on 1000*1000 records time waste: " + (System.currentTimeMillis() - start)); start = System.currentTimeMillis(); for (String s : array) { // } System.out.println("Array foreach on 1000*1000 records time waste: " + (System.currentTimeMillis() - start)); |
实验结果
第一次:
Array for i++ on 1000*1000 records time waste: 0
Array foreach on 1000*1000 records time waste: 0
第二次:
Array for i++ on 1000*1000 records time waste: 0
Array foreach on 1000*1000 records time waste: 16
第三次:
Array for i++ on 1000*1000 records time waste: 0
Array foreach on 1000*1000 records time waste: 0
foreach比for++费内存?
先引用一位哥们的说法:
every time you run into this loop, if strings is an Iterable, you will create a new Iterator instance. If you’re using an ArrayList, this is going to be allocating an object with 3 ints on your heap、浪费空间啊。
关于耗费内存的说法我是支持的,但是” with 3 ints on your heap “这个我就不能同意了,foreach语法糖实际是JVM根据对象生成一个迭代器,我们来看下源码,看下是不是多浪费了空间,浪费了多少空间,现以java.util.ArrayList为例:
public Iterator<E> iterator() { return new Itr(); ////这部分是比for++多的 } private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); //这部分是比for++多的 int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } } |
由代码可见,foreach比for++多了new了一个对象,遍历的时候多了是否遍历种被修改判断,其余操作与for++是一致的。由此可见:多浪费空间一说是纯属扯蛋。
总结
1、foreach遍历线性集合对象比for++略低,但差距非常接近;
2、foreach遍历链表集合对象比for++高的多,差距由集合对象数量决定
3、foreach遍历内存使用上会比for++多那么一点点,迭代器实际返回的是集合的数据集;