普通for,增强for,forEach,stream.forEach四种遍历方法

java8新出的循环方式,在网上有大量的道友说用流的方式效率反而更低了。

大量的结论表明,这种方式只是语法糖(for-forEach-stream三种遍历方法执行效率比较与选用思考 - ZZY1078689276的专栏 - CSDN博客
https://blog.csdn.net/ZZY1078689276/article/details/79430772)这篇文章一样的内容看了不止一次,我都不知道谁先写的。。

不过,耳听为虚,眼见为实,上代码亲自试验:

public static void main(String[] args) {
// 测试源
List sourceList = new ArrayList<>();
for (int i = 0;i<10;i++) {
sourceList.add(“第” + i + “条数据”);
}
System.out.println(“数据条数:” + sourceList.size());
long a1=System.currentTimeMillis();
for (int i = 0;i < sourceList.size();i++) doSome();
long a2=System.currentTimeMillis();
System.out.println(“普通for循环用时:” + (a2-a1));
long b1=System.currentTimeMillis();
for (String t:sourceList) doSome();
long b2=System.currentTimeMillis();
System.out.println(“增强for循环用时:” + (b2-b1));
long c1=System.currentTimeMillis();
sourceList.forEach((t)-> doSome());
long c2=System.currentTimeMillis();
System.out.println(“forEach循环用时:” + (c2-c1));

long d1=System.currentTimeMillis();
sourceList.parallelStream().forEach((t)-> doSome());
long d2=System.currentTimeMillis();
System.out.println("forEach-Stream循环用时:" + (d2-d1));

}
结果如下:

数据条数:10
普通for循环用时:0
增强for循环用时:0
forEach循环用时:43
forEach-Stream循环用时:6

好吧,数据少了点,不过结果也很明显了,使用forEach循环耗时最多,流启动也很耗时。

不过,让我们把循环次数提升至100W如何?

数据条数:1000000
普通for循环用时:3
增强for循环用时:10
forEach循环用时:46
forEach-Stream循环用时:33

forEach-Stream方式用时增加了,不过forEach用时并没有明显增加,再来一次:

数据条数:1000000
普通for循环用时:3
增强for循环用时:7
forEach循环用时:38
forEach-Stream循环用时:31

exm?forEach循环用时反而减少了是什么情况?不过今天我不研究原理,只看结论的话,for循环和增强for循环至少还是比新出的forEach-Stream要强很多的。

但这么一来,难道新功能真的只是语法糖么?

有人问我doSome()做了什么?实际上我什么都没做,但如果我真的做了什么呢?

比如等待一毫秒?

private static void doSome() {
try {
Thread.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
再来一次:

数据条数:10000
普通for循环用时:10025
增强for循环用时:10009
forEach循环用时:10067
forEach-Stream循环用时:1567

Duang!!!!!!!

forEach-Stream的效率获得了碾压式的胜利!有人说是因为jvm预热原因,但先且不论预热的是什么(通常是指启动时加载的东西),预热这种一次性的行为怎么可能取得这么大的提升?

于是,让我们打印一下doSome()的线程

ForkJoinPool.commonPool-worker-5
ForkJoinPool.commonPool-worker-4
ForkJoinPool.commonPool-worker-6
ForkJoinPool.commonPool-worker-2
main
ForkJoinPool.commonPool-worker-3
ForkJoinPool.commonPool-worker-7
ForkJoinPool.commonPool-worker-1
ForkJoinPool.commonPool-worker-6
main
ForkJoinPool.commonPool-worker-2
ForkJoinPool.commonPool-worker-3
ForkJoinPool.commonPool-worker-4
ForkJoinPool.commonPool-worker-5
ForkJoinPool.commonPool-worker-7
ForkJoinPool.commonPool-worker-1
ForkJoinPool.commonPool-worker-5
main

stream().forEach用的多线程方式,其调用线程池的时候必然会耗费更多的时间。但如果你在循环内要处理的事情很多,或者要循环调用远程接口/数据库的时候,无疑极大的提升了效率