您的位置:

Stream排序

一、Stream排序原理

Stream是Java 8引入的全新API,它对集合进行封装,可以对集合进行类似于SQL语句的操作。其中,sort()是stream中最常用的排序方法,它是一个中间操作,返回的是此流的排序视图。sort()方法有两种形式:有参形式和无参形式。在无参形式中,sort()使用自然顺序进行排序;在有参形式中,sort()使用自定义比较器进行排序。

当流中的元素数量较小,排序时间较短,但流中的元素数量逐渐增加时,排序操作将花费更多的时间。这是因为排序算法的时间复杂度为O(nlogn),因此它的性能与元素数量呈对数关系,也就是说,如果元素数量增加一倍,则排序时间将增加一个单位时间。

Stream排序算法通常使用的是归并排序,该算法的思想是将一个大的有序序列划分为两个较小的有序序列,然后对这两个有序序列进行合并,得到一个更大的有序序列。在每次合并过程中,都会使用比较器对两个有序序列进行比较,以得到更小或更大的值,最终得到一个有序序列。

二、使用Comparator进行排序

在使用Stream进行排序时,通常需要实现Comparator接口,该接口用于定义两个对象之间的比较规则。Comparator接口是一个函数式接口,可以使用lambda表达式来实现。下面是一个例子,使用Comparator对Person对象按年龄进行排序:

List people = new ArrayList<>();
people.add(new Person("John", 25));
people.add(new Person("Mary", 30));
people.add(new Person("Peter", 35));

List
    sortedPeople = people.stream()
        .sorted((p1, p2) -> p1.getAge() - p2.getAge())
        .collect(Collectors.toList());

   
  

在上面的例子中,sorted()方法使用一个比较器对流中的元素进行排序。这个比较器是一个lambda表达式,该表达式对两个Person对象进行比较,返回一个整数,用于表示它们之间的顺序。在本例中,比较器使用第一个Person对象的年龄减去第二个Person对象的年龄,如果结果为负数,则表示第一个Person对象的年龄小于第二个Person对象的年龄,排在前面。

三、使用自然排序进行排序

在Java中,每个类都可以实现Comparable接口,该接口定义了一个compareTo()方法,用于指定该类对象之间的自然顺序。如果一个类实现了Comparable接口,它的对象就可以被自然排序。下面是一个例子,使用自然排序对字符串进行排序:

List names = Arrays.asList("John", "Mary", "Peter");
List
    sortedNames = names.stream().sorted().collect(Collectors.toList());

   
  

在上面的例子中,sorted()方法没有传递任何比较器,因此使用自然排序对字符串进行排序。String类实现了Comparable接口,因此它的对象可以进行自然排序。

四、排序的稳定性

排序的稳定性指的是,在排序后,具有相同关键字的元素,其原来的相对顺序没有变化。例如,对一个包含多个人名和年龄的列表,按照年龄排序后,如果有两个人的年龄相同,则这两个人的名字应该按照原来的顺序排列。

在Stream排序中,排序的稳定性取决于所使用的排序算法。例如,如果使用Arrays.sort()对数组进行排序,该方法使用的是快速排序,该算法不保证排序的稳定性。如果要保证排序的稳定性,可以使用归并排序或插入排序等算法。

五、并行排序

Stream提供了parallel()方法,该方法用于将流转换为并行流。在使用并行流进行排序时,Stream将自动对流进行拆分,将每个子流交给线程池中的线程处理,再将处理结果合并。下面是一个例子,对一个包含大量随机数的列表进行排序:

List numbers = new Random().ints(10000000).boxed().collect(Collectors.toList());

long start = System.currentTimeMillis();
List
    sortedNumbers = numbers.parallelStream().sorted().collect(Collectors.toList());
long end = System.currentTimeMillis();

System.out.println("Time: " + (end - start) + "ms");

   
  

在上面的例子中,使用ints()方法生成一个包含1000万个随机数的列表,然后使用parallelStream()方法将其转换为并行流。在sorted()方法之后,Stream将会对每个子流进行排序,然后将排序结果合并。在本例中,使用并行流进行排序所花费的时间要比使用顺序流要少得多。