几种 for 循环的性能及耗时测试

    网上一直流传这几种循环遍历的比较,说某某这样写比较好,又说某某那样写比较好,你就那么轻易相信别人说好就好了?难道你出去时,别人给你推销说这个东西好,那你就得买?这是一个道理。鉴于这种情况,我一般都会自己去动手试试,我倒是要看看那些人说的到底对不对,这难道不是程序员必备的基本想法吗?反正,我可不想按照别人说的那样,让你怎么做就怎么做。

    在这里,我认为那些流传的几种写法在性能在的比较未必是错的,可能别人的测试是在 JDK 很早的版本之前进行的,但这都什么年代了,还在把别人 N 年前测试的数据拿来秀,太真实了。

    好了,今天要测试的就是这几种 for 循环以及一种迭代器的性能和总耗时长。首先,我把我测试的数据内容、数据量以及测试的对象和 JDK 版本介绍一下。

    测试平台:JDK1.9、数据大小 1000W 条、数据存放在 ArrayList、数据元素:Person 实体类、循环体内执行的操作时间复杂度为 O(1),数据源代码如下:

List<Person> personList = new ArrayList<>();
Person p = null;
for (int i = 0; i < 10000000; i++) {
    p = new Person("" + i, 18, 5000);
    personList.add(p);
}

    1、第一种循环遍历写法,也是我们常常这样干的:

long start = System.nanoTime();
for (int i = 0; i < personList.size(); i++) {
    String name = personList.get(i).getName();
    int salary = personList.get(i).getSalary();
    int age = personList.get(i).getAge();
}
long end = System.nanoTime();
System.out.println("耗时:" + (end - start));
  • 耗时记录(单位:纳秒)
  • 56 385 677
  • 57 089 676
  • 55 864 345

    2、第二种写法,把 size 提到外面来赋值,这种写法在源码中也很常见

long start = System.nanoTime();
int size = personList.size(); // 比上面加了一个 size 变量
for (int i = 0; i < size; i++) {
    String name = personList.get(i).getName();
    int salary = personList.get(i).getSalary();
    int age = personList.get(i).getAge();
}
long end = System.nanoTime();
System.out.println("耗时:" + (end - start));
  • 耗时记录(单位:纳秒)
  • 55 618 123
  • 56 231 455
  • 55 987 012

    3、第三种 foreach 的形式,代码量比较少,这是优点;缺点是如果要获取遍历次数,就要定义一个变量来操作

long start = System.nanoTime();
for (Person person : personList) {
    String name = person.getName();
    int salary = person.getSalary();
    int age = person.getAge();
}
long end = System.nanoTime();
System.out.println("耗时:" + (end - start));
  •  耗时记录(单位:纳秒)
  • 58 332 341
  • 56 330 566
  • 57 217 231

    4、第四种,倒序遍历,有点反常,看不习惯,不过也可能对应某些特殊场景需要。

long start = System.nanoTime();
for (int i = personList.size() - 1; i > -1; i--) {
    String name = personList.get(i).getName();
    int salary = personList.get(i).getSalary();
    int age = personList.get(i).getAge();
}
long end = System.nanoTime();
System.out.println("耗时:" + (end - start));
  • 耗时记录(单位:纳秒)
  • 54 814 125
  • 55 777 234
  • 55 624 790

     5、第五种,是迭代器的写法,也有人推荐,说性能好。

long start = System.nanoTime();
Iterator<Person> it = personList.iterator();
while (it.hasNext()) {
    Person person = it.next();
    String name = person.getName();
    int salary = person.getSalary();
    int age = person.getAge();
}
long end = System.nanoTime();
System.out.println("耗时:" + (end - start));
  • 耗时记录(单位:纳秒)
  • 57 920 341
  • 57 161 232
  • 58 355 896

    其实,从这几种测试得出的结果来看,它们之间的差距可以说是微乎其微,可以说在性能方面,几乎是一个样的。上面的时间单位是纳秒,来算一下,50 000 000纳秒相当于 0.05 秒

     而从上面的结果差距来看,他们之间的差距也就是在 0.05秒 / 10,0.005秒的差距,这个几乎可以忽略不计了吧。不是否认这些代码的贡献,这可能是前辈们在 JDK 很早之前测试的情况,那时候我估计还在上小学呢,这是一个上面概念。

    在 JDK1.9 的版本里,这几种循环遍历的性能几乎一样,可以说是一样的。不信的话,你自己动手测试一下就知道,看看自己的JDK版本,我没装过旧的版本,所以我只能对 JDK1.9 的版本来证明这几种遍历。

    还有就是写循环遍历的时候,每个人都有自己的习惯,难免产生不同的写法也是很正常的。我就比较喜欢用 foreach 的写法,看起来很简练。以上,纯属本人在测试后得到的真实数据,若觉的我有什么地方不对,欢迎指正!

    其实,我写这篇文章的目的是,我在偶然刷到了一篇文章,说 Java 的30几个性能优化知识里面提到循环遍历的性能,看了一下那测试结果(时间是18年的),大吃一惊,耗时差了几千倍,而且下面的评论还有理有据的。我就在想 jvm 优化这么差吗,我也怀疑自己之前写的那些循环遍历的代码,然后赶紧自己测试起来,发现在 JDK 版本这么高的今天,还用当年的知识误导别人,自己都没动手测试一下就随便发别人的结果,且不说别人是否是正确的,就算是错误的,转来转去都变成真的了。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值