java8学习笔记(三):sorted()与collections.sort()排序效率浅析

3,046 阅读4分钟

引言

工作中很多情况下,都需要按照某项规则对数据进行排序,常用的方式包括使用stream的sorted()方法和Collections.sort()方法等;这两种方式都可实现快速排序,但是那种方式的效率更高呢?我们来一探究竟。

前期准备

测试对比类如下:

@Data
@Builder
@ToString
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class Person {
    Integer age;
    String name;
    String skin;
}

效率测试

编码的设计思路非常简单,针对同样数量的集合,使用不同的方法,以时间差来来辨别效率。话不多说,上代码~

public class SortPerformanceTest {

    public static void main(String[] args) {
        List<Person> list = new ArrayList<>(2<<9);
        for (int i = 0; i < 1000000; i++) {
            // 随机产生0 - 1000的数
            int j = (int) (Math.random() * 1000);
            list.add(Person.builder().age(j).name("name" + i).skin("yellow" + i).build());
        }
        // 一写多读场景
        List<Person> list1 = new CopyOnWriteArrayList<>(list);
        List<Person> list2 = new CopyOnWriteArrayList<>(list);
        List<Person> list3 = new CopyOnWriteArrayList<>(list);
        List<Person> list4 = new CopyOnWriteArrayList<>(list);
        List<Person> list5 = new CopyOnWriteArrayList<>(list);
        List<Person> list6 = new CopyOnWriteArrayList<>(list);
        List<Person> list7 = new CopyOnWriteArrayList<>(list);
        long firstTiem = Instant.now().toEpochMilli();
        // 使用map + sorted()方式正序排列
        List<Integer> list1OfSorted = list1.parallelStream().map(Person::getAge).sorted().collect(Collectors.toList());
        long secondTime = Instant.now().toEpochMilli();
        System.out.println("使用map + sorted() 排列耗时为:" + (secondTime - firstTiem));
        // 使用sorted(Comparator.comparing)排序
        List<Person> list2OfSorted = list2.parallelStream().sorted(Comparator.comparing(Person::getAge)).collect(Collectors.toList());
        long thirdTime = Instant.now().toEpochMilli();
        System.out.println("使用Comparator.comparing排列耗时为:" + (thirdTime - secondTime));
        // 使用sorted(Comparator.comparingInt)排序
        List<Person> list3OfSorted = list3.parallelStream().sorted(Comparator.comparingInt(Person::getAge)).collect(Collectors.toList());
        long fourthTime = Instant.now().toEpochMilli();
        System.out.println("使用Comparator.comparingInt排列耗时为:" + (fourthTime - thirdTime));
        // 使用Collections.sort()排序
        list4.sort(Comparator.comparingInt(Person::getAge));
        long fifthTime = Instant.now().toEpochMilli();
        System.out.println("使用Collections.sort排列耗时为:" + (fifthTime - fourthTime));

        // ------------------- 倒序排列 ------------------
        List<Person> list5OfSorted = list5.parallelStream().sorted(Comparator.comparingInt(Person::getAge).reversed()).collect(Collectors.toList());
        long sixthTime = Instant.now().toEpochMilli();
        System.out.println("使用Comparator.comparingInt倒序排列耗时为:" + (sixthTime - fifthTime));
        List<Person> list6OfSorted = list6.parallelStream().sorted(Collections.reverseOrder(Comparator.comparing(Person::getAge))).collect(Collectors.toList());
        long seventhTime = Instant.now().toEpochMilli();
        System.out.println("使用Collections.reverseOrder倒序排列耗时为:" + (seventhTime - sixthTime));
        list7.sort(Comparator.comparing(Person::getAge).reversed());
        long eighthTime = Instant.now().toEpochMilli();
        System.out.println("使用Collections.sort倒序排列耗时为:" + (eighthTime - seventhTime));

    }
    
}

程序运行的结果如下:

size=50:
使用map + sorted() 排列耗时为:139,
使用Comparator.comparing排列耗时为:6,
使用Comparator.comparingInt排列耗时为:1,
使用Collections.sort排列耗时为:1
使用Comparator.comparingInt倒序排列耗时为:1,
使用Collections.reverseOrder倒序排列耗时为:1,
使用Collections.sort倒序排列耗时为:1

size=100:
使用map + sorted() 排列耗时为:54,
使用Comparator.comparing排列耗时为:30,
使用Comparator.comparingInt排列耗时为:2,
使用Collections.sort排列耗时为:1
使用Comparator.comparingInt倒序排列耗时为:55,
使用Collections.reverseOrder倒序排列耗时为:1,
使用Collections.sort倒序排列耗时为:1

size=200:
使用map + sorted() 排列耗时为:56,
使用Comparator.comparing排列耗时为:26,
使用Comparator.comparingInt排列耗时为:2,
使用Collections.sort排列耗时为:3
使用Comparator.comparingInt倒序排列耗时为:3,
使用Collections.reverseOrder倒序排列耗时为:2,
使用Collections.sort倒序排列耗时为:1

size=300:
使用map + sorted() 排列耗时为:64,
使用Comparator.comparing排列耗时为:3,
使用Comparator.comparingInt排列耗时为:1,
使用Collections.sort排列耗时为:2
使用Comparator.comparingInt倒序排列耗时为:1,
使用Collections.reverseOrder倒序排列耗时为:6,
使用Collections.sort倒序排列耗时为:1

size=1000:
使用map + sorted() 排列耗时为:59,
使用Comparator.comparing排列耗时为:40,
使用Comparator.comparingInt排列耗时为:2,
使用Collections.sort排列耗时为:3
使用Comparator.comparingInt倒序排列耗时为:4,
使用Collections.reverseOrder倒序排列耗时为:2,
使用Collections.sort倒序排列耗时为:3

size=10000:
使用map + sorted() 排列耗时为:143,
使用Comparator.comparing排列耗时为:11,
使用Comparator.comparingInt排列耗时为:18,
使用Collections.sort排列耗时为:13
使用Comparator.comparingInt倒序排列耗时为:15,
使用Collections.reverseOrder倒序排列耗时为:12,
使用Collections.sort倒序排列耗时为:7

size=100000:
使用map + sorted() 排列耗时为:198,
使用Comparator.comparing排列耗时为:109,
使用Comparator.comparingInt排列耗时为:78,
使用Collections.sort排列耗时为:65
使用Comparator.comparingInt倒序排列耗时为:77,
使用Collections.reverseOrder倒序排列耗时为:22,
使用Collections.sort倒序排列耗时为:72

size=200000:
使用map + sorted() 排列耗时为:161,
使用Comparator.comparing排列耗时为:109,
使用Comparator.comparingInt排列耗时为:101,
使用Collections.sort排列耗时为:92
使用Comparator.comparingInt倒序排列耗时为:72,
使用Collections.reverseOrder倒序排列耗时为:56,
使用Collections.sort倒序排列耗时为:112

size=1000000:
使用map + sorted() 排列耗时为:2501,
使用Comparator.comparing排列耗时为:277,
使用Comparator.comparingInt排列耗时为:276,
使用Collections.sort排列耗时为:302
使用Comparator.comparingInt倒序排列耗时为:301,
使用Collections.reverseOrder倒序排列耗时为:236,
使用Collections.sort倒序排列耗时为:401

总结

通过上述比对,可以简单得出如下结论:

  • 使用Collections.sort(Comparator<? super E> c)进行正序排列效率最高,使用stream的parallelStream().sorted(Comparator.comparingInt(xxx))次之;
  • 使用Collections.sort(Comparator.reversed())进行倒序排列效率最高;

但,在实际的业务中很多时候都不可能只涉及到一处顺序排列,特别是java8流式表达式多重使用时,所以这时便需要我们灵活选择,努力提升编码效率。但是为啥性能会有如此大的差异,这个还要后续在研究!今天做个简单总结 ...