Stream流(三更草堂)
1、案例准备
学习stream流相关内容,先准备以下的code
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode//用于后期的去重使用
// 作者
public class Author {
private Long id;// 编号
private String name;// 姓名
private Integer age;// 年龄
private String intro;// 简介
private List<Book> books;// 作品
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Book {
private Long id;
private String name;// 书名
private String category;// 分类 多个分类之间采用逗号连接
private Integer score;// 评分
private String intro;// 简介
}
public class Authors {
public static List<Author> getAuthors() {
//数据初始化
Author author = new Author(1L, "蒙多", 33, "一个从菜刀中明悟哲理的祖安人", null);
Author author2 = new Author(2L, "亚拉索", 15, "狂风也追逐不上他的思考速度", null);
Author author3 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);
Author author4 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);
//书籍列表
List<Book> books1 = new ArrayList<>();
List<Book> books2 = new ArrayList<>();
List<Book> books3 = new ArrayList<>();
books1.add(new Book(1L, "刀的两侧是光明与黑暗", "哲学,爱情", 88, "用一把刀划分了爱恨"));
books1.add(new Book(2L, "一个人不能死在同一把刀下", "个人成长,爱情", 99, "讲述如何从失败中明悟真理"));
books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
books2.add(new Book(4L, "吹或不吹", "爱情,个人传记", 56, "一个哲学家的恋爱观注定很难把他所在的时代理解"));
books3.add(new Book(5L, "你的剑就是我的剑", "爱情", 56, "无法想象一个武者能对他的伴侣这么的宽容"));
books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?"));
books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?"));
author.setBooks(books1);
author2.setBooks(books2);
author3.setBooks(books3);
author4.setBooks(books3);
List<Author> authorList = new ArrayList<>(Arrays.asList(author, author2, author3, author4));
return authorList;
}
}
2、快速入门
需求:
- 打印所有年龄小于18的作家的名字,并且要注意去重。
public class Demo01 {
// 打印所有年龄小于18的作家的名字,并且要注意去重。
public static void main(String[] args) {
Authors.getAuthors().stream()
.distinct()// 去重
.filter(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getAge() <= 18;
}
})// 过滤年龄条件
.forEach(new Consumer<Author>() {
@Override
public void accept(Author author) {
System.out.println(author.getName());
}
});// 遍历打印
}
}
public class Demo01 {
// 打印所有年龄小于18的作家的名字,并且要注意去重。
public static void main(String[] args) {
Authors.getAuthors().stream()
.distinct()// 去重
.filter(author -> author.getAge() <= 18)// 过滤年龄条件
.forEach(author -> System.out.println(author.getName()));// 遍历打印
}
}
3、常用操作
(1)创建流
- 单列集合(继承Collection接口):集合对象.stream()
- 数组:Arrays.stream(数组对象)或者Stream.of(数组对象)
- 双列集合(继承Map接口):转换成单列集合后再创建
public class Demo02 {
// 单列集合
public void test01() {
List<Author> authors = Authors.getAuthors();
Stream<Author> stream = authors.stream();
}
// 数组
public void test02() {
Integer[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
Stream<Integer> stream01 = Arrays.stream(arr);
Stream<Integer> stream02 = Stream.of(arr);
}
// 双列集合
public void test03() {
Map<String, Integer> map = new HashMap<>();
map.put("aaa", 1);
map.put("bbb", 2);
map.put("ccc", 3);
Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();
}
}
(2)中间操作
- filter:可以对流中的元素进行条件过滤,复合过滤条件的才能继续留在流中;
- map:可以把对流中的元素进行计算或者转换;
- distinct:可以去除流中的重复元素,注意:distinct方法是依赖Object的equal方法来判断是否是相同对象的,需要注意重写equals方法;
- sorted:可以对流中的元素进行排序,注意:如果调用空参的sorted()方法,需要流中的元素是实现了Comparable接口;
- limit:可以设置流的最大长度,超出的部分将被抛弃;
- skip:跳过流中的前n个元素,返回剩下的元素;
- flatMap:map只能把一个对象转换成另一个对象来作为流中的元素,而flatMap可以把一个对象转换成多个对象作为流中的元素。
public class Demo03 {
public static void main(String[] args) {
filter();
System.out.println("====================");
map();
System.out.println("====================");
distinct();
System.out.println("====================");
sorted();
System.out.println("====================");
limit();
System.out.println("====================");
skip();
System.out.println("====================");
flatMap();
}
// filter
public static void filter() {
// 打印所有姓名长度大于1的作家的姓名
Authors.getAuthors().stream()
.filter(author -> author.getName().length() > 1)
.forEach(author -> System.out.println(author.getName()));
}
// map
public static void map() {
// 打印所有作家的年龄加10
Authors.getAuthors().stream()
.map(author -> author.getAge())
.map(age -> age + 10)
.forEach(age -> System.out.println(age));
}
// distinct
public static void distinct() {
// 打印所有作家的姓名,并且要求其中不能有重复元素
Authors.getAuthors().stream()
.distinct()
.forEach(author -> System.out.println(author.getName()));
}
// sorted
public static void sorted() {
// 对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素
Authors.getAuthors().stream()
.sorted((a, b) -> b.getAge() - a.getAge())
.forEach(author -> System.out.println(author.getName()));
}
// limit
public static void limit() {
// 对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素,然后打印其中年龄最大的两个作家的姓名
Authors.getAuthors().stream()
.distinct()
.sorted((a, b) -> b.getAge() - a.getAge())
.limit(2)
.forEach(author -> System.out.println(author.getName()));
}
// skip
public static void skip() {
// 打印除了年龄最大的作家的其他作家,要求不能有重复元素,并且按照年龄降序排序
Authors.getAuthors().stream()
.distinct()
.sorted((a, b) -> b.getAge() - a.getAge())
.skip(1)
.forEach(author -> System.out.println(author.getName()));
}
// flatMap
public static void flatMap() {
// 打印所有书籍的名字,并且要求对重复的元素进行去重
Authors.getAuthors().stream()
.flatMap((Function<Author, Stream<Book>>) author -> author.getBooks().stream())
.distinct()
.forEach(book -> System.out.println(book.getName()));
System.out.println("====================");
// 打印现有数据的所有分类,要求对分类去重,不能出现这种格式:哲学,爱情
Authors.getAuthors().stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.flatMap(book -> Arrays.stream(book.getCategory().split(",")))
.distinct().forEach(System.out::println);
}
}
蒙多
亚拉索
====================
43
25
24
24
====================
蒙多
亚拉索
易
====================
蒙多
亚拉索
易
易
====================
蒙多
亚拉索
====================
亚拉索
易
====================
刀的两侧是光明与黑暗
一个人不能死在同一把刀下
那风吹不到的地方
吹或不吹
你的剑就是我的剑
风与剑
====================
哲学
爱情
个人成长
个人传记
(3)终结操作
- forEach:对流中的元素进行遍历操作,通过传入的参数去指定对遍历到的元素进行什么具体操作;
- count:获取当前流中元素的个数;
- max&min:用来计算流中的最值;
- collect:把当前流转换成一个集合;
- anyMatch:用来判断是否有任何符合匹配条件的元素,结果为boolean类型;
- allMatch:可以用来判断是否都符合匹配条件,结果为boolean类型,如果都符合结果为true,否则结果为false;
- noneMatch:可以用来判断流中的元素都不符合匹配条件,如果都不符合结果为true,否则结果为false;
- findAny:获取流中的任意一个元素,该方法没有办法保证获取的一定是流中的第一个元素;
- findFirst:获取流中的第一个元素;
- reduce:对流中的数据按照你指定的计算方式计算出一个结果,作用是把stream中的元素给组合起来,可以传入一个初始值,它会按照我们的计算方式依次拿流中的元素和在初始化值的基础上进行计算,计算结果再和后面的元素计算。
public class Demo04 {
public static void main(String[] args) {
forEach();
System.out.println("==============================");
System.out.println(count());
System.out.println("==============================");
max_min();
System.out.println("==============================");
collect();
System.out.println("==============================");
System.out.println(anyMatch());
System.out.println("==============================");
System.out.println(allMatch());
System.out.println("==============================");
System.out.println(noneMatch());
System.out.println("==============================");
findAny();
System.out.println("==============================");
findFirst();
System.out.println("==============================");
reduce();
}
// forEach
public static void forEach() {
// 输出所有作家的名字
Authors.getAuthors().stream()
.distinct()
.forEach(author -> System.out.println(author.getName()));
}
// count
public static Long count() {
// 打印这些作家的所出书籍的数目,注意删除重复的元素
return Authors.getAuthors().stream()
.distinct()
.flatMap(author -> author.getBooks().stream())
.distinct()
.count();
}
// max&min
public static void max_min() {
// 分别获取这些作家所出书籍的最高分和最低分并打印
Optional<Integer> max = Authors.getAuthors().stream()
.distinct()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.max((o1, o2) -> o1 - o2);
System.out.println("最大值=" + max.get());
Optional<Integer> min = Authors.getAuthors().stream()
.distinct()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.min((o1, o2) -> o2 - o1);
System.out.println("最小值=" + min.get());
}
// collect
public static void collect() {
// 获取一个存放所有作者名字的List集合
List<String> list = Authors.getAuthors().stream()
.distinct()
.map(author -> author.getName())
.collect(Collectors.toList());
System.out.println(list);
// 获取一个所有书名的set集合
Set<String> set = Authors.getAuthors().stream()
.distinct()
.flatMap(author -> author.getBooks().stream())
.distinct()
.map(book -> book.getName())
.collect(Collectors.toSet());
System.out.println(set);
// 获取一个map集合,map的key为作者名,value为List<Book>
Map<String, List<Book>> map = Authors.getAuthors().stream()
.distinct()
.collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
System.out.println(map);
}
// anyMatch
public static boolean anyMatch() {
// 判断是否有年龄在29以上的作家
return Authors.getAuthors().stream()
.distinct()
.anyMatch(author -> author.getAge() > 29);
}
// allMatch
public static boolean allMatch() {
// 判断是否所有的作家都是成年人
return Authors.getAuthors().stream()
.distinct()
.allMatch(author -> author.getAge() > 18);
}
// noneMatch
public static boolean noneMatch() {
// 判断作家是否都没有超过100岁
return Authors.getAuthors().stream()
.distinct()
.noneMatch(author -> author.getAge() > 100);
}
// findAny
public static void findAny() {
// 获取任意一个大于18的作家,如果存在就输出作家的名字
Authors.getAuthors().stream()
.distinct()
.filter(author -> author.getAge() > 18)
.findAny()
.ifPresent(author -> System.out.println(author.getName()));
}
// findFirst
public static void findFirst() {
// 获取一个年龄最小的作家,并输出作家的姓名
Authors.getAuthors().stream()
.sorted((a, b) -> a.getAge() - b.getAge())
.findFirst()
.ifPresent(author -> System.out.println(author.getName()));
}
// reduce
public static void reduce() {
// 求所有作者年龄的和
System.out.println(Authors.getAuthors().stream()
.map(author -> author.getAge())
.distinct()
.reduce(0, (Integer::sum)));
// 求所有作者中年龄的最大值
Authors.getAuthors().stream()
.distinct()
.map(author -> author.getAge())
.reduce(Integer::max)
.ifPresent(age -> System.out.println(age));
// 求所有作者中年龄的最小值
Authors.getAuthors().stream()
.distinct()
.map(author -> author.getAge())
.reduce(Integer::min)
.ifPresent(age -> System.out.println(age));
}
}
蒙多
亚拉索
易
==============================
6
==============================
最大值=100
最小值=100
==============================
[蒙多, 亚拉索, 易]
[那风吹不到的地方, 你的剑就是我的剑, 刀的两侧是光明与黑暗, 风与剑, 吹或不吹, 一个人不能死在同一把刀下]
{亚拉索=[Book(id=3, name=那风吹不到的地方, category=哲学, score=85, intro=带你用思维去领略世界的尽头), Book(id=3, name=那风吹不到的地方, category=哲学, score=85, intro=带你用思维去领略世界的尽头), Book(id=4, name=吹或不吹, category=爱情,个人传记, score=56, intro=一个哲学家的恋爱观注定很难把他所在的时代理解)], 蒙多=[Book(id=1, name=刀的两侧是光明与黑暗, category=哲学,爱情, score=88, intro=用一把刀划分了爱恨), Book(id=2, name=一个人不能死在同一把刀下, category=个人成长,爱情, score=99, intro=讲述如何从失败中明悟真理), Book(id=3, name=那风吹不到的地方, category=哲学, score=85, intro=带你用思维去领略世界的尽头)], 易=[Book(id=5, name=你的剑就是我的剑, category=爱情, score=56, intro=无法想象一个武者能对他的伴侣这么的宽容), Book(id=6, name=风与剑, category=个人传记, score=100, intro=两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?), Book(id=6, name=风与剑, category=个人传记, score=100, intro=两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?)]}
==============================
true
==============================
false
==============================
true
==============================
蒙多
==============================
易
==============================
62
33
14
4、注意事项
- 惰性求值:如果没有终结操作,只有中间操作是不会得到执行的;
- 流是一次性的:一旦一个流对象经过一个终结操作后,这个流就不能再被使用;
- 不会影响原数据:流中可以对数据进行很多的处理,但是不会影响原来集合中的元素的。