为什么list.sort()比Stream().sorted()更快?

news2024/11/15 9:48:23

真的更好吗?

先简单写个demo

List<Integer> userList = new ArrayList<>();
        Random rand = new Random();
        for (int i = 0; i < 10000 ; i++) {
            userList.add(rand.nextInt(1000));
        }
        List<Integer> 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<Integer> userList = new ArrayList<>();
        Random rand = new Random();
        for (int i = 0; i < 10000 ; i++) {
            userList.add(rand.nextInt(1000));
        }
        List<Integer> 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

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

都不能。

两种方式都不能证明什么。

使用这种方式在很多场景下是不够的,某些场景下,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<Integer> 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<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. 绝大多数场景下,几百几千几万的数据,开心就好,怎么方便怎么用,没有必要去计较这点性能差异。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/834907.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python爬虫遇到重定向问题解决办法汇总

在进行Python爬虫任务时&#xff0c;遇到重定向问题是常见的问题之一。重定向是指在发送请求时&#xff0c;服务器会返回一个新的URL&#xff0c;将请求重新定向到该URL。为了帮助您解决这个问题&#xff0c;本文将提供一些实用的解决办法&#xff0c;并给出相关的代码示例&…

java linq多字段排序时间比较

public static void main(String[] args) {//100万条数据List<CrmInvestSaleUserCount> waitAssignUserList new ArrayList<>();for (int i 0; i < 1000000; i) {waitAssignUserList.add(new CrmInvestSaleUserCount().setSales_username("test" i…

小孩学python课程需要多久,儿童学python哪个机构好

本篇文章给大家谈谈小孩学python课程需要多久&#xff0c;以及儿童学python语言能做什么&#xff0c;希望对各位有所帮助&#xff0c;不要忘了收藏本站喔。 学习儿童python编程越来越受欢迎&#xff0c;原因有很多&#xff0c;对于孩子来说&#xff0c;Python是一种很好的编程语…

深入探究DDD领域建模的方法:从概念到实践

目录 &#xff11;.什么是领域建模&#xff1f; &#xff12;.领域驱动设计的基本原则 &#xff13;.领域建模的核心概念 &#xff14;.DDD领域建模方法 &#xff15;.领域建模中的挑战与解决方案 &#xff16;.DDD领域建模的优势和适用场景 &#xff17;.DDD领域建模的…

【枚举+01 trie树】CF1658 D2

Problem - D2 - Codeforces 题意&#xff1a; 给定一个区间[l, r]和r - l 1个数&#xff0c;问是否存在一个数 x &#xff0c;使得这些数异或上 x 之后为[l, r]的一个排列 思路&#xff1a; 这种有关一个集合和异或操作的&#xff0c;都可以试试字典树 我们将所有数插入到…

C++ 左值和右值

C 左值和右值 左值、右值左值引用、右值引用std::move()std::move()的实现引用折叠 完美转发forward()的实现函数返回值是左值还是右值如何判断一个值是左值还是右值 左值、右值 在C11中所有的值必属于左值、右值两者之一&#xff0c;右值又可以细分为纯右值、将亡值。在C11中…

Python实现蚁群优化算法,求解旅行商问题

文章目录 蚁群算法蚂蚁的基本变量蚂蚁的优化流程蚁群优化验证与可视化 蚁群算法 蚁群算法是Colori A等人在1991年提出的&#xff0c;通过模仿蚂蚁觅食行为&#xff0c;抽象出信息素这一奖惩机制&#xff0c;从而赋予蚂蚁智能Agent的身份&#xff0c;使之得以在最佳路线问题中大…

Windows环境下Node.js二进制版安装教程

文章目录 前言一 下载Node.js二 设置环境变量三 配置全局安装和缓存路径四 设置仓库 前言 新版的Node.js已自带npm&#xff0c;就在Node.js下载完成解压后的文件内&#xff0c;的node_modules包中。 npm的作用&#xff1a;是对Node.js依赖的包进行管理&#xff0c;类似maven。…

使用 CausalPy 进行因果推理

这篇文章通过一个实际的例子简要介绍了因果推理&#xff0c;这个例子来自于《The Brave and True》一书&#xff0c;我们使用 CausalPy 来实现。 因果推理是从观察数据中估计因果效应的过程。对于任何给定的个体&#xff0c;我们只能观察到一种结果。另一种结果对我们来说是隐藏…

蓝牙ble tips2-UUID GATT(service和CHARACTERISTIC) profile相关概念介绍

服务和特性 低功耗蓝牙设备之间通信&#xff0c;都是基于服务和特性。一个蓝牙设备中可以包含若干个服务&#xff0c;一个服务中可以包含若干个特性&#xff0c;每一个服务或者特性都要有一个UUID。蓝牙的数据交互都是基于一个个特性进行的&#xff0c;数据交互的方式有五种&a…

超全面的高精度行星减速机结构、原理、功能以及优势解析

行星减速机是运动控制系统中连接伺服电机和应用负载的一种机械传动组件&#xff0c;具有高减速比、良好的传动特性、结构紧凑、体积小、重量轻、可靠性高、低噪音等优点&#xff0c;广泛用于电机、汽车、机器人及各种工业机械中&#xff0c;以实现高效率和稳定性。 一、什么是…

Ubuntu20.04安装ROS Noetic 版本安装记录

用的是VMWare的20.04的Ubuntu虚拟机&#xff0c;打算安装一下Noetic 版本的ROS学习一下。B站有个视频可以参考一下&#xff1a;在Ubuntu20.04上安装ROS机器人操作系统-Noetic但是基本也是参考中文文档安装&#xff0c;步骤相比网上的教程更权威Ubuntu install of ROS Noetic&am…

LeetCode--HOT100题(20)

目录 题目描述&#xff1a;48. 旋转图像&#xff08;中等&#xff09;题目接口解题思路代码 PS: 题目描述&#xff1a;48. 旋转图像&#xff08;中等&#xff09; 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#x…

echarts图表渐变色 + 每个柱子不同颜色设置

echarts柱状图&#xff0c;默认所有柱子都是同一个颜色&#xff0c;显示效果差强人意&#xff0c;本文介绍如果修改成为每个柱子添加不同的颜色&#xff0c;以及如何添加渐变色&#xff0c;丰富图表的显示鲜果。先看效果&#xff1a; 每个柱子颜色不同 每个柱子都有自己的渐变…

【论文阅读】基于 NeRF 的 3D 重建的批判性分析

【论文阅读】基于 NeRF 的 3D 重建的批判性分析 Abstract1. Introduction2. The State of the Art2.1. Photogrammetric-Based Methods2.2. NeRF-Based Methods 3. Analysis and Evaluation Methodology3.1. Proposed Methodology3.2. Metrics3.3. Testing Objects 4. Comparis…

HTML5(H5)的前生今世

目录 概述HTML5与其他HTML的区别CSS3与其他CSS版本的区别总结 概述 HTML5是一种用于构建和呈现网页的最新标准。它是HTML&#xff08;超文本标记语言&#xff09;的第五个版本&#xff0c;于2014年由万维网联盟&#xff08;W3C&#xff09;正式推出。HTML5的前身可以追溯到互联…

[MAUI 项目实战] 手势控制音乐播放器: 动画

吸附动画 还记的上一章节所描述的拖拽物&#xff08;pan&#xff09;和坑&#xff08;pit&#xff09;吗&#xff1f;“”吸附“”这是一个非常拟物的过程&#xff0c;当拖拽物品接近坑区域的边缘时&#xff0c;物体就会由于重力或是引力作用会滑落&#xff0c;吸附在坑里。 …

MINIO安装(centos7)

步骤1&#xff1a;安装wget 在开始安装MinIO之前&#xff0c;需要安装wget命令行工具。可以使用以下命令在CentOS系统中安装wget&#xff1a; sudo yum install wget 步骤2&#xff1a;下载MinIO wget https://dl.minio.org.cn/server/minio/release/linux-amd64/minio 将下…

最新[新手入门教程] JDK8u381的下载安装以及环境变量的配置

JAVA从入门到精通 各位新手们大家好&#xff0c;今天来为大家介绍一下JDK8u381的下载安装以及环境变量的配置 【前言】 1.是不是不知道什么是Java&#xff1f; 官方定义&#xff1a; Java是一门面向对象的高级编程语言&#xff0c;不仅吸收了C语言的各种优点&#x…

硬盘格式化后能恢复数据吗?这4个方法可以帮到你!

“前几天一不小心对硬盘进行了格式化操作&#xff0c;但是我很多重要的文件都保存在里面了呀&#xff01;硬盘格式化之后还能进行恢复吗&#xff1f;快帮帮我&#xff01;” 硬盘格式化会将存储在硬盘上的数据全部清除&#xff0c;并将文件系统重置为初始状态。那么&#xff0c…