8

Java stream 和 for 循环效率对比问题

 3 years ago
source link: https://www.oschina.net/question/4464549_2320608
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Java stream 和 for 循环效率对比问题

惊叫唤 发布于 12/24 14:05
阅读 648

针对同一个集合,用 stream 操作两次得到两个不同条件筛选出来的集合和map,和一次for循环就搞定搞定的效率对比。

虽然stream写起来链式操作很舒服,但效率在不同数据量下的体现效果是不一样的,以下为我的测试代码:

    @Test
    public void testStreamAndFor() {
        List<Student> 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 = Instant.now();
            Map<Long, Student> idMapOfStream = studentList.stream()
                    .collect(Collectors.toMap(Student::getId, v -> v));

            List<Integer> studentAgeListOfStream = studentList.stream()
                    .map(Student::getAge)
                    .collect(Collectors.toList());

            long streamRunTime = Duration.between(streamStart, Instant.now()).toMillis();
            System.out.println("第" + (i + 1) + "次:" + "stream 耗时:" + streamRunTime);

            Instant forStart = Instant.now();
            int size = studentList.size();
            Map<Long, Student> idMapOfFor = new HashMap<>(size);
            List<Integer> ageListOfFor = new ArrayList<>();
            for (Student student : studentList) {
                idMapOfFor.put(student.getId(), student);
                ageListOfFor.add(student.getAge());
            }
            long forRunTime = Duration.between(forStart, Instant.now()).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);
        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来操作更加具有效率。但是小弟还是有点不明白原因是为何,求高人指点一二


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK