java流和循环效率_Javastream和for循环效率对⽐问题针对同⼀个集合,⽤ stream 操作两次得到两个不同条件筛选出来的集合和map,和⼀次for循环就搞定搞定的效率对⽐。
虽然stream写起来链式操作很舒服,但效率在不同数据量下的体现效果是不⼀样的,以下为我的测试代码:
@Test
public void testStreamAndFor() {
List studentList = new ArrayList<>();
// 初始数据量
int listSize = 100000;
// 测试次数,以便求出平均运⾏时长
int testTimes = 5;
for (int i = 0; i < listSize; i++) {
Student student = new Student();
student.setId(i + 1);
student.setStudentName("name" + i);
student.setAge(i);
studentList.add(student);
}
BigDecimal streamTotalRunTime = new BigDecimal("0");
BigDecimal forTotalRunTime = new BigDecimal("0");
for (int i = 0; i < testTimes; i++) {
Instant streamStart = w();
Map idMapOfStream = studentList.stream()
.
Map(Student::getId, v -> v));
List studentAgeListOfStream = studentList.stream()
.map(Student::getAge)
.List());
long streamRunTime = Duration.between(streamStart, w()).toMillis();
System.out.println("第" + (i + 1) + "次:" + "stream 耗时:" + streamRunTime);
Instant forStart = w();
int size = studentList.size();
Map idMapOfFor = new HashMap<>(size);
List ageListOfFor = new ArrayList<>();
for (Student student : studentList) {
idMapOfFor.Id(), student);
ageListOfFor.Age());
}
long forRunTime = Duration.between(forStart, w()).toMillis();
System.out.println("第" + (i + 1) + "次:" + "for 耗时:" + forRunTime);
streamTotalRunTime = streamTotalRunTime.add(new BigDecimal(streamRunTime + ""));
forTotalRunTime = forTotalRunTime.add(new BigDecimal(forRunTime + ""));
}
System.out.println("list长度为:" + listSize + ", 总共测试次数:" + testTimes);
System.out.println("stream总运⾏时间(ms) :" + streamTotalRunTime);
System.out.println("for总运⾏时间(ms) :" + forTotalRunTime);
java stream
BigDecimal streamAverageRunTime = streamTotalRunTime.divide(new BigDecimal(testTimes + ""), 2, BigDecimal.ROUND_HALF_UP);
System.out.println("stream平均每次运⾏时间(ms) :" + streamAverageRunTime);
BigDecimal forAverageRunTime = forTotalRunTime.divide(new BigDecimal(testTimes + ""), 2, BigDecimal.ROUND_HALF_UP);
System.out.println("for平均每次运⾏时间(ms) :" + forAverageRunTime);
}
当数据量为10w,测试5次的结果输出:
第1次:stream 耗时:81
第1次:for 耗时:13
第2次:stream 耗时:15
第2次:for 耗时:23
第3次:stream 耗时:7
第3次:for 耗时:11
第4次:stream 耗时:7
第4次:for 耗时:13
第5次:stream 耗时:9
第5次:for 耗时:6
list长度为:100000, 总共测试次数:5
stream总运⾏时间(ms) :119
for总运⾏时间(ms) :66
stream平均每次运⾏时间(ms) :23.80
for平均每次运⾏时间(ms) :13.20
当数据量为100w,测试5次的输出结果:
第1次:stream 耗时:165
第1次:for 耗时:1296
第2次:stream 耗时:447
第2次:for 耗时:62
第3次:stream 耗时:363
第3次:for 耗时:359
第4次:stream 耗时:61
第4次:for 耗时:350
第5次:stream 耗时:389
第5次:for 耗时:43
list长度为:1000000, 总共测试次数:5
stream总运⾏时间(ms) :1425
for总运⾏时间(ms) :2110
stream平均每次运⾏时间(ms) :285.00
for平均每次运⾏时间(ms) :422.00
所有运⾏时长单位均为ms。综上测试结果,当数据量少于百万级别的,⼀次for循环来筛选数据效率更⾼,当数据量达到⼋万级别,还是使⽤stream来操作更加具有效率。但是⼩弟还是有点不明⽩原因是为何,求⾼⼈指点⼀⼆
回答
其实⽤ stream 主要是很多写起来代码⽐较简洁,如果数据量⼤的话,还能很容易转换为并⾏流,帮你做了多线程,不需要⾃⼰代码去写多线程了
感谢⽼哥:+1:
我⽤Java11运⾏100W数据量的结果是⼆者性能差别不⼤, 如果堆调⼤⼀些的话, for性能更好, 说明stream需要更多的内存分配
这。。我还是⽤的万年java8~~⽼哥的这种⽅式,可以借鉴⼀⼿
你这代码,确定 for 和 stream ⼲的是同样的事情? Student::getAge 也发下看看
回复 @是码农还是程序员呢 : 我觉得你的结果很有问题,所以才需要你发出来看下,如果不发那就算了,我对你的结果存疑回复 @乌龟壳 :代码⼀直都是如我所说那样操作的回复 @是码农还是程序员呢 : 你可以把代码补充到问题⾥,光说意义不⼤,很多性能问题都是细节上的问题for循环和stream都是将Student::getId放⼊新的map中(id为key,Student对象为value),以及将Student::getAge放⼊新的List中。两种⽅式都是对相同字段做的相同操作。
语义和使⽤便捷性,是优先考虑。⼤多数的性能问题,都不在这些suger
对于数据量和操作⽅式来讲,应该是有最优解,在性能差异不⼤的情况下肯定选择语义和使⽤便捷性,但性能差距过⼤,还是性能优先。就测试demo来看,stream筛选数据到新的数据结构(两种或多种)中,需要使⽤stream操作两次或多次,但使⽤for的话只需遍历⼀次就可以将原数据中所有想要的数据提取出来,所以这种情况下,是否应该要考虑for来提⾼效率呢
数值变化差值也太⼤了吧第⼀次for1200+ 第五次43?
我⼜再⼀次测试了下确实如此,但我将最外层遍历(测试次数)取消掉,通过⼿动运⾏来增加测试次数后,每⼀次运⾏时长都是⼏⼗毫秒,差值并不⼤。所以应该是最外层遍历导致这样的差值,但这只是表⾯上的原因,底层原因就有点迷惑了
这测试的太草率了。
确实有⼀点粗糙。。⼤佬可有好的建议:smile:
for循环⾥把map的size直接就给定了,扩容要⽐stream少
在for循环⾥⼲了两件事,stream调⽤了两次
数据在10w级别,第⼀次调⽤for确实要⽐stream快,后续来看两者有持平的趋势
两次环境同时执⾏,运⾏环境状态不可控
可以分多次、时间线更长⼀点,多线程条件下在对⽐执⾏(模拟真实的应⽤场景)
不⽤测,stream内部就是for循环
不要把Stream 当做是循环,这2个并不是⼀回事,Stream是流,更像是⼀个管⼦,循环只是循环
就题主测试的场景来说,性能上必然是循环更快的。
Stream并不是⼀个循环,⽽是⼀个连接上下游的管⼦,⽐如说,我们使⽤Files.lines 来按⾏遍历⼀个⽂件的时候,他并不是⼀次性把⽂件加载到内存,解析成⼀个按⾏的集合,再进⾏遍历的,⽽是基于迭代器,每读取解析完⼀⾏数据,就发送到Stream流⾥,下游,map也好,flatMap也好forEach也好等等,都是每当上游发送⼀个数据,就处理⼀个数据,因为是流式的,看起来就跟遍历⼀起,其实这2个并不⼀样
那么Stream为什么能实现集合遍历呢?跟上边说的⽂件遍历性质是⼀样的,就是直接借助集合的迭代器,把集合的数据⼀个个发送到流⾥,然后下游处理,形成了看是遍历的操作,Stream处理要完成消息的传递,⾥⾯还要有其他很多辅助东西的处理,⽐如上游消息已经全发完了得通知到下游吧。从⽽就遍历上来说,Stream的性能是不可能⽐循环更快的
看下并⾏流的100W的结果,不要只是拿顺序流来测试
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论