java的for下标循环遍历和foreach循环遍历测试

java的for下标循环遍历和foreach循环遍历测试,到底哪个效率更高,下面写了代码测试:

测试针对   数组、ArrayList、LinkedList三种,分别做for下标循环遍历和foreach循环遍历:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 数组、ArrayList、LinkedList三种,分别做for下标循环遍历和foreach循环遍历
 */
public class TestFor {

	/**
	 * 数组和ArrayList的大小
	 */
	private final int num = 1000000;

	/**
	 * LinkedList的大小
	 */
	private final int numLinked = num / 10;

	private final int[] testArray = new int[num];

	private final List<Integer> testArrayList = new ArrayList<Integer>();

	private final List<Integer> testLinkList = new LinkedList<Integer>();

	private int test = 0;

	private void init() {
		for (int i = 0; i < num; i++) {
			testArray[i] = 0;
			testArrayList.add(0);
		}
		for (int i = 0; i < numLinked; i++) {
			testLinkList.add(0);
		}

	}

	private void testIndexArray() {
		final long startTime = System.currentTimeMillis();
		for (int i = 0; i < num; i++) {
			test = testArray[i];
		}
		final long stopTime = System.currentTimeMillis();
		System.out.println("下标数组                               " + (stopTime - startTime));
	}

	private void testIterateArray() {
		final long startTime = System.currentTimeMillis();
		for (final int i : testArray) {
			test = testArray[i];
		}
		final long stopTime = System.currentTimeMillis();
		System.out.println("foreach数组                         " + (stopTime - startTime));
	}

	private void testIndexArrayList() {
		final long startTime = System.currentTimeMillis();
		for (int i = 0; i < num; i++) {
			test = testArrayList.get(i);
		}
		final long stopTime = System.currentTimeMillis();
		System.out.println("下标ArrayList       " + (stopTime - startTime));
	}

	private void testIterateArrayList() {
		final long startTime = System.currentTimeMillis();
		for (final int i : testArrayList) {
			test = testArrayList.get(i);
		}
		final long stopTime = System.currentTimeMillis();
		System.out.println("foreachArrayList    " + (stopTime - startTime));
	}

	private void testIndexLinkList() {
		final long startTime = System.currentTimeMillis();
		for (int i = 0; i < numLinked; i++) {
			test = testLinkList.get(i);
		}
		final long stopTime = System.currentTimeMillis();
		System.out.println("下标LinkList        " + (stopTime - startTime));
	}

	private void testIterateLinkList() {
		final long startTime = System.currentTimeMillis();

		for (final int i : testLinkList) {
			test = testLinkList.get(i);
		}
		final long stopTime = System.currentTimeMillis();
		System.out.println("foreachLinkList     " + (stopTime - startTime));
	}

	public static void main(final String[] args) {
		final TestFor test = new TestFor();
		test.init();

		test.testIndexArray();
		test.testIterateArray();

		test.testIndexArrayList();
		test.testIterateArrayList();

		test.testIndexLinkList();
		test.testIterateLinkList();

	}
}



结果:

下标数组                       2
foreach数组                 3
下标ArrayList               7
foreachArrayList         20
下标LinkList                5721
foreachLinkList          7


注意上述结果:数组和ArrayList容量为1000000,LinkedList是1000000 / 10(十分之一,因为遍历LinkedList实在太慢)


数组           :下标比foreach快,差别较小;

ArrayList   :下标比foreach快,差别较大;

LinkedList:foreach比下标快,差别较大;


Java 中的 foreach 语法是 iterator(迭代器)的变形用法(可以看看反编译之后的代码),也就是说上面的 foreach 与下面的代码等价:

for (Iterator<Integer> i = list.iterator(); i.hasNext();) {
    sum += ((Integer)iterator.next()).intValue();
}



lsit.iterator() 返回的迭代器对象是什么呢?查看JDK源码知道,ArrayList 类继承于 AbstractList 类,AbstracList 对 iterator 方法实现如下(ArrayList 类并没有重写该方法):

public Iterator<E> iterator() {
    return new Itr();
}


方法直接创建一个 Itr 对象并将其返回,Itr 类其实是 AbstractList 类的一个内部类,Itr 类实现了 Iterator 接口,Itr 类部分源代码如下:

private class Itr implements Iterator<E> {
    /**
     * Index of element to be returned by subsequent call to next.
     */
    int cursor = 0;

    /**
     * Index of element returned by most recent call to next or
     * previous.  Reset to -1 if this element is deleted by a call
     * to remove.
     */
    int lastRet = -1;

    public boolean hasNext() {
        return cursor != size();
    }

    public E next() {
        checkForComodification();
        try {
            E next = get(cursor);
            lastRet = cursor++;
            return next;
        } catch (IndexOutOfBoundsException e) {
            checkForComodification();
            throw new NoSuchElementException();
        }
    }
}

从上面代码可以看出,迭代器同样也是通过对指向数组(ArrayList 是通过数组实现的)的下标进行递增来遍历整个数组的,这和通过下标方式访问列表计算平均值的方法是一样的,但是区别在于,迭代器需要调用 hasNext() 函数来判断指向数组的下标是否移到了数组末尾,而下标访问方式中并不需要对此进行检查;除此之外,在迭代器的  next() 方法中也出现了下标访问方式没有的 checkForComodification() 方法和 lastRet 变量赋值操作。这也就是通过 foreach 方式遍历耗时的原因。


那么ArrayList和LinkedList的区别是什么?

ArrayList数组实现了RandomAccess接口(随机存取接口),标识着ArrayList是一个可以随机存取的列表,即元素之间没有关联,即两个位置相邻的元素之间没有相互依赖关系,可以随机访问和存储。 

LinkedList类也是一个列表,它是有序存取的,实现了双向链表、每个数据节点都有单个数据项,前面节点的引用(Previous Node)、本节点元素(Node Element)、后续节点的引用(Next Node)。也就是说LinkedList两个元素本来就是有联系的,我知道你存在,你知道我存在


说对于ArrayList,需要先创建一个迭代器容器,然后屏蔽内部遍历细节,对外提供hasNext、next等方法。 

问题是ArrayList实现了RandomAccess接口,表明元素之间本没有关系,为了使用迭代器就需要强制建立一种互相“知晓”的关系,比如上一个元素可以判断是否有下一个元素,以及下一个元素是什么等关系,这也就是通过foreach遍历耗时的原因。


所以,以后如果是数组或ArrayList就用下标循环遍历,如果是LinkedList就用foreach循环遍历。当然 这只是在考虑性能时候的做法,如果不考虑性能还用foreach比较好,代码简洁。


over







  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值