细说 Stream 中的用法
大概了解了 Stream流 的一个过程后,让我们来一起当回厂长,去 "流水线" 中的每一个生产车间去检验检验,瞅瞅这个 "流水线" 都能干些什么?
说实话,当这个图弄上来的时候,我都不知道该从哪个先开始...
既然前面 Stream流 初体验 中用到了去重,那么就先从 distinct()
这个先开始吧!
先来搭一些 "前期准备" 吧...
-
基础类
@Data @AllArgsConstructor public class Book { // 书籍名称 private String bookName; // 作者 private String author; // 作者的年龄 private Integer age; // 书的价格 private Integer price; } 复制代码
我这里用的是 Lombok 中的
@Data
里面包含了:Getter、Setter、RequiredArgsConstructor、ToString、EqualsAndHashCode -
公用的集合 (内容自己定义吧,不重要... 整几个相同的就行)
@Test public List<Book> getBooks(){ List<Book> books = new ArrayList<>(); Collections.addAll(books, new Book("笑傲江湖", "金庸", 99, 365), new Book("笑傲江湖", "金庸", 99, 365), new Book("神雕侠侣", "金庸", 99, 365), new Book("雪中悍刀行","烽火戏诸侯",35,320), new Book("雪中悍刀行","烽火戏诸侯",35,320), new Book("剑来","烽火戏诸侯",35,320), new Book("西游记","吴承恩",56,198), new Book("三国演义","罗贯中",58,230), new Book("水浒传","施耐庵",55,200), new Book("红楼梦","曹雪芹",66,280) ); return books; } 复制代码
2.4.1 distinct()
先看源码上的解释:
返回不同元素组成的流 (即去重嘛~),规则就是:Object 中的 equals 方法。
所以需要注意的是:当我们实际要去用的时候,是需要重写 hashCode 与 equals 的,它会先比较 hashCode,hashCode 相同时则使用 equals 方法比较 (在 Lombok 就一个 @Data 啥都不用管了)
-
怎么用呢?代码如下:
@Test public void test13(){ List<Book> books = getBooks(); books.stream() .distinct() .forEach(System.out::println); } 复制代码
-
注意!!一定要重写 hashCode 和 equals ,不然就会失效了。如果使用 Lombok 的小伙伴可以试试把 Book 类中的
@Data
给注释了,加上个@ToString
去看看没有重写的结果就知道了//@Data @ToString @AllArgsConstructor public class Book { private String bookName; private String author; private Integer age; private Integer price; } 复制代码
再跑一遍,就会看到这个集合原来怎么样,现在也还是怎么样 (
distinct()
失效了)。
2.4.2 sorted()
这个就是排序。在 Stream 中 sorted() 有两个重载方法,一个无参的,默认按自然排序 (即正序排序);另一个需要实现 Comparator 这个函数式接口,自己定义排序规则
Stream<T> sorted();
Stream<T> sorted(Comparator<? super T> comparator);
复制代码
那么我们就整个场景:按作者的年龄来排序
-
首先来瞅瞅无参的这个,先浅看一波源码
可以看到
this.isNaturalSort = true
是否是自然排序设置了为 true,即下面那里调用个的这个方法:Comparator.naturalOrder()
这个不扯那么远,大概的意思就是无参的这个排序 Stream 中默认使用了自然排序 (也就是正序了)
-
那既然他默认帮咱们做了排序了,那我们直接调来瞅瞅是啥样子的效果?
@Test public void test14(){ List<Book> books = getBooks(); books.stream() .sorted() .forEach(System.out::println); } 复制代码
运行!映入眼前的是一片红...
不要慌,源码上有一句注释:Will throw CCE when we try to sort if T is not Comparable ,即如果T不可比较,当我们尝试排序时将抛出CCE (也就是当前的ClassCastException)。
确实咱把一个对象 Book 都扔过去了,谁知道你要比较啥?所以我们可以这样做:让 Book 这个类实现的 Comparable 接口 ,通过接口提供的 compareTo 方法来进行排序。
-
所以这个 Book 对象可以这样:
@Data @AllArgsConstructor public class Book implements Comparable<Book>{ private String bookName; private String author; private Integer age; private Integer price; @Override public int compareTo(@NotNull Book o) { return age - o.age; } } 复制代码
-
再次运行,你会发现运行成功,且效果也与预期一样
或许有些好兄弟已经发现了!咱们这样做,说到底还是通过实现了 Comparable接口 从而自定义了排序的规则,似乎和
sorted()
没啥关系。说白了,就是一顿 "脱裤子放屁" 的 XX 操作...确实,当前的场景下用这个无参的去排序本身就是不太合理的,它感觉更适合在某些较为单一的数据中去使用。所以在不一样的场景下,使用不一样的方法是很有必要的
-
在 Stream 中还给我们提供了另一个方法,那么此时我们就可以这样做了:
@Test public void test14(){ List<