引言
工作中很多情况下,都需要按照某项规则对数据进行排序,常用的方式包括使用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流式表达式多重使用时,所以这时便需要我们灵活选择,努力提升编码效率。但是为啥性能会有如此大的差异,这个还要后续在研究!今天做个简单总结 ...