性能比较 之 Java中不同的For循环

For循环是Java等编程语言中非常常见的控制 Stream 语句。我将不介绍“ for循环”的基本知识,因为它超出了本文的范围,我们大多数人已经很清楚这一点。

在这篇文章中,我将列出在日常编程习惯中用于循环的各种方法,然后将它们与一组类似的数据进行比较,以了解它们的相对性能。

使用循环的不同方式

据我所知,我列出了4种不同的方式。如果您还知道其他方式,请通过评论告知我。

1)对于每个陈述

在此技术中,对java 5中引入的每个语句都使用了高级。作为下一个核心Java访谈问题,也请学习此内容。

private static List<Integer> list = new ArrayList<>();
for(Integer i : list)
{
	// do other stuff
}

2)在条件中使用list.size()

private static List<Integer> list = new ArrayList<>();
for(int j = 0; j < list.size() ; j++)
{
	//do stuff
}

3)初始化另一个具有大小的局部变量

private static List<Integer> list = new ArrayList<>();
int size = list.size();
for(int j = 0; j < size ; j++)
{
	//do stuff
}

4)将计数器的初始值初始化为列表大小

private static List<Integer> list = new ArrayList<>();
for(int j = list.size(); j > size ; j--)
{
	//do stuff
}

比较所有类型的性能

我正在创建一个arraylist,并用1千万个Integer实例填充它。然后,我将使用所有四种方式遍历列表。这样,我们将能够了解性能上的差异。

执行环境:

  • Java 7
  • Eclipse朱诺
package com.how2codex.demo.core;

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

public class ForLoopPerformanceTest
{
	private static List<Integer> list = new ArrayList<>();
	private static long startTime;
	private static long endTime;
	static
	{
		for(int i=0; i < 1_00_00_000; i++)
		{
			list.add(i);
		}
	}
	@SuppressWarnings("unused")
	public static void main(String[] args)
	{
		//Type 1
		startTime = Calendar.getInstance().getTimeInMillis();
		for(Integer i : list)
		{
			//
		}
		endTime = Calendar.getInstance().getTimeInMillis();
		System.out.println("For each loop :: " + (endTime - startTime) + " ms");

		//Type 2
		startTime = Calendar.getInstance().getTimeInMillis();
		for(int j = 0; j < list.size() ; j++)
		{
			//
		}
		endTime = Calendar.getInstance().getTimeInMillis();
		System.out.println("Using collection.size() :: " + (endTime - startTime) + " ms");

		//Type 3
		startTime = Calendar.getInstance().getTimeInMillis();
		int size = list.size();
		for(int j = 0; j < size ; j++)
		{
			//System.out.println(j);
		}
		endTime = Calendar.getInstance().getTimeInMillis();
		System.out.println("Using [int size = list.size(); int j = 0; j < size ; j++] :: " + (endTime - startTime) + " ms");

		//Type 4
		startTime = Calendar.getInstance().getTimeInMillis();
		for(int j = list.size(); j > size ; j--)
		{
			//System.out.println(j);
		}
		endTime = Calendar.getInstance().getTimeInMillis();
		System.out.println("Using [int j = list.size(); j > size ; j--] :: " + (endTime - startTime) + " ms");
	}
}

当上述程序运行时,控制台中的输出如下:

对于每个循环::: 110 ms 
使用collection.size():: 37 ms 
使用[int size = list.size(); int j = 0; j <大小; j ++] :: 4毫秒
使用[int j = list.size(); j>大小; j--] :: 1毫秒

显然,后两种方式在性能方面是领先的,而对于每条语句,[类型1]与其他三种方式相比是最昂贵的操作。

更新:

表现差异的原因

最后两种类型3和4的味道差别很小,应视为相同。它们最初都获取集合的大小。然后在循环中使用此大小值检查条件。

类型2每次都使用size()方法调用,因此在运行时会带来一些开销。尽管JVM也将此代码优化为内联调用和其他优化,并且size方法只是列表实例的size属性的一种获取方法。即使它带来了一些要在机器级代码上执行的语句,这也有所不同。

类型1是最昂贵的类型,简单的推理就是使用内部为每个循环创建的迭代器。创建一个迭代器并调用iterator.get()会增加大多数成本,而其他三种类型的直接访问都不会涉及这些成本。

saigon has written 1445 articles

Leave a Reply