设为首页 加入收藏

TOP

为什么 list.sort() 比 stream().sorted() 要更快?测试结果把我惊呆了!(二)
2023-09-09 10:25:37 】 浏览:54
Tags:list.sort stream .sorted
etSimpleName()) .result("SortBenchmark.json") .mode(Mode.All) .resultFormat(ResultFormatType.JSON) .build(); new Runner(opt).run(); } @Setup public void init() { arrayList = new ArrayList<>(); Random random = new Random(); for (int i = 0; i < operationSize; i++) { arrayList.add(random.nextInt(10000)); } } @Benchmark public void sort(Blackhole blackhole) { arrayList.sort(Comparator.comparing(e -> e)); blackhole.consume(arrayList); } @Benchmark public void streamSorted(Blackhole blackhole) { arrayList = arrayList.stream().sorted(Comparator.comparing(e -> e)).collect(Collectors.toList()); blackhole.consume(arrayList); } }

性能测试结果:

可以看到,list sort()效率确实比stream().sorted()要好。

为什么更好?

流本身的损耗

java的stream让我们可以在应用层就可以高效地实现类似数据库SQL的聚合操作了,它可以让代码更加简洁优雅。

但是,假设我们要对一个list排序,得先把list转成stream流,排序完成后需要将数据收集起来重新形成list,这部份额外的开销有多大呢?

我们可以通过以下代码来进行基准测试

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.results.format.ResultFormatType;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Warmup(iterations = 2, time = 1)
@Measurement(iterations = 5, time = 5)
@Fork(1)
@State(Scope.Thread)
public class SortBenchmark3 {

    @Param(value = {"100", "10000"})
    private int operationSize; // 操作次数
    private static List<Integer> arrayList;

    public static void main(String[] args) throws RunnerException {
        // 启动基准测试
        Options opt = new OptionsBuilder()
                .include(SortBenchmark3.class.getSimpleName()) // 要导入的测试类
                .result("SortBenchmark3.json")
                .mode(Mode.All)
                .resultFormat(ResultFormatType.JSON)
                .build();
        new Runner(opt).run(); // 执行测试
    }

    @Setup
    public void init() {
        // 启动执行事件
        arrayList = new ArrayList<>();
        Random random = new Random();
        for (int i = 0; i < operationSize; i++) {
            arrayList.add(random.nextInt(10000));
        }
    }

    @Benchmark
    public void stream(Blackhole blackhole) {
        arrayList.stream().collect(Collectors.toList());
        blackhole.consume(arrayList);
    }

    @Benchmark
    public void sort(Blackhole blackhole) {
        arrayList.stream().sorted(Comparator.comparing(Integer::intValue)).collect(Collectors.toList());
        blackhole.consume(arrayList);
    }

}

方法stream测试将一个集合转为流再收集回来的耗时。

方法sort测试将一个集合转为流再排序再收集回来的全过程耗时。

测试结果如下:

可以发现,集合转为流再收集回来的过程,肯定会耗时,但是它占全过程的比率并不算高。

因此,这部只能说是小部份的原因。

排序过程

我们可以通过以下源码很直观的看到。

  • 1 begin方法初始化一个数组。
  • 2 accept 接收上游数据。
  • 3 end 方法开始进行排序。

这里第3步直接调用了原生的排序方法,完成排序后,第4步,遍历向下游发送数据。

所以通过源码,我们也能很明显地看到,stream()排序所需时间肯定是 > 原生排序时间。

只不过,这里要量化地搞明白,到底多出了多少,这里得去编译jdk源码,在第3步前后将时间打印出来。

这一步我就不做了。

感兴趣的朋友可以去测一下。

不过我觉得这两点也能很好地回答,为什么list.sort()比Stream().sorted()更快。

补充说明:

1、 本文说的stream()流指的是串行流,而不是并行流;

2、 绝大多数场景下,几百几千几万的数据,开心就好,怎么方便怎么用,没有必要去计较这点性能差异;

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Interpreter Pattern 下一篇Visitor Pattern

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目