解密排序之争:原生List VS 流行Stream,谁更高效?

很多人都说list sort()排序比stream().sorted()排序性能更好,但是到底为什么呢。

本文章里面的所有测试案例都是基于:JDK8

先来一个简单版demo,看看效果

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

public class Main {

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        Random rand = new Random();
        for (int i = 0; i < 10000; i++) {
            list.add(rand.nextInt(1000));
        }
        List<Integer> streamList = new ArrayList<>();
        streamList.addAll(list);

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

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

}

输出结果(万级):

stream.sort耗时:77ms
list.sort()耗时:6ms

输出结果(十万级):

stream.sort耗时:143ms
list.sort()耗时:76ms

输出结果(百万级):

stream.sort耗时:443ms
list.sort()耗时:269ms

再来一个复杂版本的demo

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

public class Test {

    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();
        Random rand = new Random();
        for (int i = 0; i < 10000000; i++) {
            User user = new User();
            user.setId("id" + i);
            user.setSort(rand.nextInt(10000000));
            userList.add(user);
        }

        List<User> streamUserList = new ArrayList<>();
        streamUserList.addAll(userList);

        Long streamStartTime = System.currentTimeMillis();
        streamUserList.stream().sorted(Comparator.comparing(User::getSort)).collect(Collectors.toList());
        System.out.println("stream.sort耗时:" + (System.currentTimeMillis() - streamStartTime) + "ms");

        Long startTime = System.currentTimeMillis();
        userList.sort(Comparator.comparing(User::getSort));
        System.out.println("list.sort()耗时:" + (System.currentTimeMillis() - startTime) + "ms");
    }


}

class User {
    private String id;
    private Integer sort;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Integer getSort() {
        return sort;
    }

    public void setSort(Integer sort) {
        this.sort = sort;
    }
}

输出结果(万级):

stream.sort耗时:48ms
list.sort()耗时:4ms

输出结果(十万级):

// 第一次
stream.sort耗时:100ms
list.sort()耗时:105ms

// 第二次
stream.sort耗时:115ms
list.sort()耗时:119ms

输出结果(百万级):

stream.sort耗时:627ms
list.sort()耗时:434ms

在一些情况下,List原生排序可能比使用流(stream)的排序更高效,这是由于以下几个原因:

  • 避免了流的额外开销:使用流的排序需要创建一个流对象,并在排序操作上应用中间操作和终端操作。这涉及到创建和维护流的状态,以及对元素进行中间操作的处理。相比之下,原生排序直接对列表进行排序,无需创建额外的对象或执行中间操作。
  • 优化的底层算法:原生排序通常使用高效的底层排序算法,例如快速排序(QuickSort)或归并排序(MergeSort)。这些算法在大多数情况下都具有较好的性能,并且经过了多年的优化和改进。相比之下,流的排序可能使用不同的排序算法,例如使用稳定排序算法,但其性能可能不如原生排序算法。
  • 数据访问模式:原生排序直接在列表上进行排序,这样可以充分利用计算机内存的局部性原理。它可以有效地访问和操作连续的内存块,减少了缓存不命中和内存访问的开销。相比之下,流的排序可能需要频繁地访问和操作元素,这可能导致更多的缓存不命中和内存访问开销。

以上的比较是一般情况下的观察结果,并不是绝对的。

在某些情况下,使用流的排序可能与原生排序具有相近的性能,特别是当使用并行流进行排序时,可以利用多核处理器的并行计算能力。

此外,流的排序具有更好的可读性和可维护性,尤其在函数式编程风格的代码中。

因此,在选择使用哪种排序方式时,需要根据具体的应用场景和需求进行权衡和选择。

最好在自己的场景下模拟测试一下,写的多了;后面就更加有把握更加清晰

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值