Stream 操作过程中,有可能会对元素进行排序,这点 Stream 支持的也不输集合。考虑到流内操作只有在终止操作时才会触发导致不便调试,Stream 也提供了偷窃利器 peek 来方便我们调试。
sorted
方法定义
Stream<T> sorted();
Stream<T> sorted(Comparator<? super T> comparator);
sorted
提供了两个方法,一个无参,一个需要传入比较器。两种方法运行过后,都可以将流内的元素排序。
使用举例
根据文档来看,sorted() 会将流内的元素进行自然排序,同时要求元素必须实现 Comparable
接口。看到这里,问题就来了,什么是自然排序?为什么要实现 Comparable
接口?我们来实验一下。
1 | public void sortedStringTest() { |
程序输出:
[am, i, sorted]
看来,确实按照字母的顺序来排序了。可是,如果元素没有实现 Comparable
又是什么情况呢?
1 | public void sortedNotComparableTest() { |
大事不妙,程序抛异常了:
Exception in thread “main” java.lang.ClassCastException: StudentNotComparable cannot be cast to java.lang.Comparable
at java.util.Comparators$NaturalOrderComparator.compare(Comparators.java:47)
at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
at java.util.TimSort.sort(TimSort.java:220)
at java.util.Arrays.sort(Arrays.java:1512)
LowB 的我决定一探源码究竟。经过几步跳转,找到如下关键代码:
1 | OfRef(AbstractPipeline<?, T, ?> upstream) { |
好家伙,原来,排序过程中需要比较器。那从元素对象身上又是怎么取到比较器的呢?
1 | enum NaturalOrderComparator implements Comparator<Comparable<Object>> { |
看来,猜测的没错了,之所以需要元素对象实现 Comparable
,就是要用 compareTo
方法来排序,这就是所谓的自然排序。
好了,明白了,我们再来看一下带有 Comparable
时运行结果。
1 | public void sortedComparableTest() { |
此时,运行正确,程序依次输出 15,23
两个数字。
sorted(Comparator<? super T> comparator)
经过了上面的原理探究,这个带有比较器方法的原理盲猜也可以猜到了:直接使用传入的比较器进行排序。来,试验一下。
1 | public void sortedWithComparatorTest() { |
果然,如果元素未实现 Comparable
接口,传入比较器之后,程序就正常运行了,依次输出 15,23
两个数字。
你以为至此就结束了吗?No,此时的我忽然冒出了另一个想法,如果元素实现了 Comparable
,此时又传入了比较器,排序时以哪个为准?盲猜一下:以传入的比较器为准,毕竟走的是传了比较器的方法。
1 | public void sortedWithComparatorTest2() { |
验证了一下,传入一个和 Comparable
相反的比较器,程序依次输出 23,15
两个数字,我们的盲猜是正确的。
为什么我能猜这么准?因为以前我们研究过 TreeMap
啊,原理都是一样的:Java 集合分析之 Map - 这个 Map 有顺序(LinkedHashMap 和 TreeMap)
peek
方法定义
Stream<T> peek(Consumer<? super T> action);
peek
方法可以将流元素取出并进行消费。看起来和 foreach
是一样,都传一个 Comsumer
,不同的是,peek
方法然后返回 Stream
,这也就意味着,我们对流进行取值,不影响流内元素继续流转,所以就可以用作 debug 了。
使用举例
1 | public void peekTest() { |
在这个过程中,我们先取出了各个字符串的长度并打印,最后,将所有长度转成一个 List,并最终打印。
1
2
6
[1, 2, 6]
总结
- sorted 方法可以对流内的元素进行排序
- 如果不传比较器,sorted 的元素需实现 Comparable,排序按照 compareTo 方法来排序
- 如果 sorted 方法传入了比较器,排序时以比较器为准
- 偷窃利器 peek 可以用于对流 debug,peek 不影响程序运行中间状态及最终结果
注:本文配套代码可在
github
查看:stream-and-lambda