网易首页 > 网易号 > 正文 申请入驻

面试官问:为什么list.sort()比Stream().sorted()更快?

0
分享至

看到一个评论,里面提到了list.sort()和list.strem().sorted()排序的差异。

说到list.sort()排序比stream().sorted()排序性能更好。

但没说到为什么。

有朋友也提到了这一点。

本文重新开始,先问是不是,再问为什么。

真的更好吗?

先简单写个 demo。

List userList = new ArrayList<>();
Random rand = new Random();
for (int i = 0; i < 10000 ; i++) {
userList.add(rand.nextInt(1000));
}
List userList2 = new ArrayList<>();
userList2.addAll(userList);

Long startTime1 = System.currentTimeMillis();
userList2.stream().sorted(Comparator.comparing(Integer::intValue)).collect(Collectors.toList());
System.out.println("stream.sort耗时:"+(System.currentTimeMillis() - startTime1)+"ms");

Long startTime = System.currentTimeMillis();
userList.sort(Comparator.comparing(Integer::intValue));
System.out.println("List.sort()耗时:"+(System.currentTimeMillis()-startTime)+"ms");

输出

stream.sort耗时:62ms
List.sort()耗时:7ms

由此可见 list 原生排序性能更好。

能证明吗?

不一定吧。

再把 demo 变换一下,先输出stream.sort。

List userList = new ArrayList<>();
Random rand = new Random();
for (int i = 0; i < 10000 ; i++) {
userList.add(rand.nextInt(1000));
}
List userList2 = new ArrayList<>();
userList2.addAll(userList);

Long startTime = System.currentTimeMillis();
userList.sort(Comparator.comparing(Integer::intValue));
System.out.println("List.sort()耗时:"+(System.currentTimeMillis()-startTime)+"ms");

Long startTime1 = System.currentTimeMillis();
userList2.stream().sorted(Comparator.comparing(Integer::intValue)).collect(Collectors.toList());
System.out.println("stream.sort耗时:"+(System.currentTimeMillis() - startTime1)+"ms");

此时输出变成了。

List.sort()耗时:68ms
stream.sort耗时:13ms

这能证明上面的结论错误了吗?

都不能。另外,推荐公众号Java精选,回复java面试,获取在线面试资料,支持随时随地刷题。

两种方式都不能证明到底谁更快。

使用这种方式在很多场景下是不够的,某些场景下,JVM 会对代码进行 JIT 编译和内联优化。

Long startTime = System.currentTimeMillis();
...
System.currentTimeMillis() - startTime

此时,代码优化前后执行的结果就会非常大。

基准测试是指通过设计科学的测试方法、测试工具和测试系统,实现对一类测试对象的某项性能指标进行定量的和可对比的测试。

基准测试使得被测试代码获得足够预热,让被测试代码得到充分的 JIT 编译和优化。

下面是通过 JMH 做一下基准测试,分别测试集合大小在 100,10000,100000 时两种排序方式的性能差异。

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.*;
import java.util.concurrent.ThreadLocalRandom;
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 SortBenchmark {
@Param(value = {"100", "10000", "100000"})
private int operationSize;
private static List arrayList;
public static void main(String[] args) throws RunnerException {
// 启动基准测试
Options opt = new OptionsBuilder()
.include(SortBenchmark.class.getSimpleName())
.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 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. 绝大多数场景下,几百几千几万的数据,开心就好,怎么方便怎么用,没有必要去计较这点性能差异。

    作者:是奉壹呀 https://juejin.cn/post/7262274383287500860

    公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者。如有侵权,请联系,笔者会第一时间删除处理!

    最近有很多人问,有没有读者交流群!加入方式很简单,公众号Java精选,回复“加群”,即可入群!

    (微信小程序):3000+道面试题,包含Java基础、并发、JVM、线程、MQ系列、Redis、Spring系列、Elasticsearch、Docker、K8s、Flink、Spark、架构设计等,在线随时刷题!

    特别推荐:专注分享最前沿的技术与资讯,为弯道超车做好准备及各种开源项目与高效率软件的公众号,「大咖笔记」,专注挖掘好东西,非常值得大家关注。点击下方公众号卡片关注。

    文章有帮助的话,点在看,转发吧!

    特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

    Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

    相关推荐
    热点推荐
    6场5负!世界杯两大黑马面临降级和出局,意大利葡萄牙渐入佳境

    6场5负!世界杯两大黑马面临降级和出局,意大利葡萄牙渐入佳境

    嗨皮看球
    2026-10-08 18:39:54
    一切都说通了,美方爆猛料,对委内瑞拉和伊朗出手,全是因为中国

    一切都说通了,美方爆猛料,对委内瑞拉和伊朗出手,全是因为中国

    显微镜下看世界
    2026-10-08 09:58:41
    吴石行刑前,据说汤恩伯两次向老蒋求情,蒋说:最多保障家眷周全

    吴石行刑前,据说汤恩伯两次向老蒋求情,蒋说:最多保障家眷周全

    优趣纪史记
    2026-09-30 06:42:21
    陈乔恩长文回应前经纪人喊话:“我真的没有恨你,你一而再再而三地提起我,其中不免带着很多添油加醋的毁谤”

    陈乔恩长文回应前经纪人喊话:“我真的没有恨你,你一而再再而三地提起我,其中不免带着很多添油加醋的毁谤”

    韩小娱
    2026-10-08 13:46:44
    才知道胡歌当时留学是被做局了!林依晨出现那一刻,袁弘、刘涛脸色直接变了,胡歌背对舞台3分钟

    才知道胡歌当时留学是被做局了!林依晨出现那一刻,袁弘、刘涛脸色直接变了,胡歌背对舞台3分钟

    书咚咚
    2026-10-04 18:37:15
    赵今麦泳装照被嘲像纸尿裤?人家不是没穿好,是童星滤镜碎了一地

    赵今麦泳装照被嘲像纸尿裤?人家不是没穿好,是童星滤镜碎了一地

    手工制作阿歼
    2026-10-06 14:42:44
    2026的楼市,跟大家开了一个大玩笑,卖房的人开始崩溃,很多人后悔了

    2026的楼市,跟大家开了一个大玩笑,卖房的人开始崩溃,很多人后悔了

    巢客HOME
    2026-10-09 05:00:03
    西媒爆料,穆帅严厉训话姆巴佩,告诫姆巴佩要低调;皇马再曝更衣室冲突,“2名球星大打出手”

    西媒爆料,穆帅严厉训话姆巴佩,告诫姆巴佩要低调;皇马再曝更衣室冲突,“2名球星大打出手”

    福酱的小时光
    2026-10-08 17:46:23
    突发!Anthropic重磅新规:辱骂Claude直接封号

    突发!Anthropic重磅新规:辱骂Claude直接封号

    新智元
    2026-10-09 08:18:44
    德国民众若是最终选择了魏德尔,那将是德国的灾难!

    德国民众若是最终选择了魏德尔,那将是德国的灾难!

    扶苏聊历史
    2026-10-06 11:10:05
    巴西大选卢拉48.43%领先,进入决选的不是博索纳罗长子

    巴西大选卢拉48.43%领先,进入决选的不是博索纳罗长子

    王姐懒人家常菜
    2026-10-09 10:47:20
    何超欣晒哥嫂全家福!奚梦瑶全身戴满金首饰饰,一双儿女红衣喜气

    何超欣晒哥嫂全家福!奚梦瑶全身戴满金首饰饰,一双儿女红衣喜气

    翰飞观事
    2026-10-09 09:42:40
    我大半辈子没嫁人,替去世的未婚夫守着老宅,前天有个小伙突然跑来,什么都没说只丢下一个旧布袋,我打开一看,眼泪止不住地流

    我大半辈子没嫁人,替去世的未婚夫守着老宅,前天有个小伙突然跑来,什么都没说只丢下一个旧布袋,我打开一看,眼泪止不住地流

    墨染尘香
    2026-10-06 15:12:34
    齐沃:我低估了逆转那不勒斯的消耗,当时我该给全队放半天假

    齐沃:我低估了逆转那不勒斯的消耗,当时我该给全队放半天假

    懂球帝
    2026-10-08 06:21:44
    官方直播!广东宏远VS山东高速,亚帅被迫单外援迎战,班顿试金石

    官方直播!广东宏远VS山东高速,亚帅被迫单外援迎战,班顿试金石

    体坛小快灵
    2026-10-09 08:03:27
    核弹已到位!泽连斯基发现大事不妙,不止朝鲜,普京又获一更强援

    核弹已到位!泽连斯基发现大事不妙,不止朝鲜,普京又获一更强援

    至死不渝的爱情
    2026-10-09 04:02:14
    翁帆终于坦白!杨振宁离世后最后悔的不是没怀孕生子,而是这件事

    翁帆终于坦白!杨振宁离世后最后悔的不是没怀孕生子,而是这件事

    郭蛹包工头
    2026-10-08 11:59:03
    机枪扫射一波不行,还要再补枪!明珍珍竟然狡辩自己"无知和愚昧"

    机枪扫射一波不行,还要再补枪!明珍珍竟然狡辩自己"无知和愚昧"

    墨策史
    2026-10-08 20:47:48
    午后,大面积涨停!最新研判

    午后,大面积涨停!最新研判

    金融界
    2026-10-08 15:55:29
    广西最美的大学,却因改名被当成野鸡大学,整个校区像4a景区

    广西最美的大学,却因改名被当成野鸡大学,整个校区像4a景区

    侃故事的阿庆
    2026-10-09 05:01:32
    2026-10-09 12:04:49
    Java精选
    Java精选
    一场永远也演不完的戏
    1802文章数 3859关注度
    往期回顾 全部

    头条要闻

    ICC院长赤根智子被判刑并通缉 俄要求荷兰等将其移交

    头条要闻

    ICC院长赤根智子被判刑并通缉 俄要求荷兰等将其移交

    体育要闻

    30天30队·鹈鹕:胖虎又一年“如果”

    娱乐要闻

    蔡康永回应,装都不装了!

    财经要闻

    鬼故事再现?OpenAI营收被爆巨大预期差

    科技要闻

    字节"干扰模型训练"实习生融资近2亿元

    汽车要闻

    不想改车又不想撞衫 来看看小鹏P7+的黑武士版

    态度原创

    健康
    家居
    亲子
    教育
    军事航空

    痘坑留下后,还能填平吗?

    家居要闻

    2026建博会(广州) 公装联探展交流活动

    亲子要闻

    启蒙早教玩具视频:小小迪学会了跳绳

    教育要闻

    首年招生617分,新校区开办后,川师附中的竞争力有增强吗

    军事要闻

    直击南部战区海军某部重装空投训练

    无障碍浏览 进入关怀版