java中for、foreach(增强for)和stream中foreach的性能和原理

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 20:50   1537   0
for循环是java出生的时候就已经支持了,在jdk 1.5中开始支持 foreach 循环,foreach 在一定程度上简化了集合的遍历,但是由于场景的局限性不能完全替代 for 循环,stream是jdk 1.8中开始支持的,功能强大,效率也还行。
public static void main(String[] args) {
        List<Integer> array = new ArrayList<Integer>();
        List<Integer> link = new LinkedList<Integer>();

        long startTime = 0;
        long endTime = 0;
        int num = 150000;

        startTime=System.currentTimeMillis();
        for(int i=0; i<num; i++) {
            array.add(i);
        }
        endTime=System.currentTimeMillis();
        System.out.println("ArrayList add 花费时间: " + (endTime - startTime));

        startTime=System.currentTimeMillis();
        for(int i=0; i<num; i++) {
            link.add(i);
        }
        endTime=System.currentTimeMillis();
        System.out.println("LinkedList add 花费时间: " + (endTime - startTime));

        startTime=System.currentTimeMillis();
        for(int i=0; i<num; i++) {
            array.get(i);
        }
        endTime=System.currentTimeMillis();
        System.out.println("for 遍历  ArrayList get 花费时间: " + (endTime - startTime));

        startTime=System.currentTimeMillis();
        for(int i=0; i<num; i++) {
            link.get(i);
        }
        endTime=System.currentTimeMillis();
        System.out.println("for 遍历 LinkedList get 花费时间: " + (endTime - startTime));

        startTime=System.currentTimeMillis();
        for(int i : array) {
//            System.out.print(i+"\r");
        }
        endTime=System.currentTimeMillis();
        System.out.println("forEach 遍历  ArrayList get 花费时间: " + (endTime - startTime));

        startTime=System.currentTimeMillis();
        for(int i : link) {
//            System.out.print(i+"\r");
        }
        endTime=System.currentTimeMillis();
        System.out.println("forEach 遍历 LinkedList get 花费时间: " + (endTime - startTime));

        startTime=System.currentTimeMillis();
        array.stream().forEach(item -> {});
        endTime=System.currentTimeMillis();
        System.out.println("stream 遍历 LinkedList get 花费时间: " + (endTime - startTime));

        startTime=System.currentTimeMillis();
        link.stream().forEach(item -> {});
        endTime=System.currentTimeMillis();
        System.out.println("stream 遍历 LinkedList get 花费时间: " + (endTime - startTime));
    }

运行结果

ArrayList:ArrayList是采用数组的形式保存对象的,这种方式将对象放在连续的内存块中,所以插入和删除时比较麻烦,当然在新增的时候遇到需要扩容也是麻烦的,查询比较方便。
LinkList:LinkList是将对象放在独立的空间中,而且每个空间中还保存前后一个空间的索引,也就是数据结构中的链表结构,插入和删除比较方便,但是查找很麻烦,要从第一个开始遍历。


运行结果表明

  • 用for循环arrayList 15万次花费时间:3毫秒;用for循环linkList 15万次花费时间:9579毫秒。
  • 用foreach循环arrayList 15万次花费时间:5毫秒;用foreach循环linkList 15万次花费时间:2毫秒。
  • 用stream中foreach循环arrayList 15万次花费时间:37毫秒。 用foreach循环linkList 15万次花费时间:3毫秒。

循环ArrayList时,普通for循环比foreach循环花费的时间要少一点,stream耗时明显偏大。
循环LinkList时,stream和foreach循环花费的时间差不多,普通for耗时明显大了好多倍。

for循环是通过下标来遍历获取对应的元素,ArrayList是数组结果所以下标获取很快,LinkedList是链表结构,每次通过下标去获取是都是从第一个节点开始往后查找,所以耗时多。
foreach循环是通过迭代器来遍历的,遍历ArrayList时需要先将数组转为对应的引用类型,因为数组没有实现Iterable接口,遍历LinkedList时直接通过顺序IO来遍历的,所以遍历耗时差不多。
stream循环是通过可分迭代器Spliterator来遍历,分为并行流和普通的顺序流,为了实现强大的功能必然对性能有所影响,所以并不是最快的。

结论

  1. 需要循环数组结构的数据时,建议使用普通for循环,因为for循环采用下标访问,对于数组结构的数据来说,采用下标访问稍微好点,而且还可以满足对list本身的修改。
  2. 需要循环链表结构的数据时,一定不要使用普通for循环,这种做法很糟糕,数据量大的时候有可能会导致系统崩溃,foreach循环性能虽好但是无法修改list本身,可以优先考虑使用stream。
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP