Stream流
- 一.概述
- 二.数据准备
- 二.Stream流的创建
-
- [2.1 单列集合创建Stream流.](#2.1 单列集合创建Stream流.)
- [2.2 数组创建Stream流](#2.2 数组创建Stream流)
- [2.3 双列集合创建Stream流](#2.3 双列集合创建Stream流)
- [三. 中间操作.](#三. 中间操作.)
-
- [3.1 filter(过滤操作)](#3.1 filter(过滤操作))
- [3.2 map(计算或者转换)](#3.2 map(计算或者转换))
- [3.3 distinct(去重操作)](#3.3 distinct(去重操作))
- [3.4 sorted(排序操作)](#3.4 sorted(排序操作))
- [3.5 limit (设置流的长度)](#3.5 limit (设置流的长度))
- [3.6 skip(跳过前n个元素)](#3.6 skip(跳过前n个元素))
- [3.7 flatMap(一个对象转为多个对象)](#3.7 flatMap(一个对象转为多个对象))
- 四.终结操作
-
- [4.1 forEach(遍历流中的每一个元素)](#4.1 forEach(遍历流中的每一个元素))
- [4.2 count(获取流中元素的个数)](#4.2 count(获取流中元素的个数))
- [4.3 max和min(获取流中的最大值或最小值)](#4.3 max和min(获取流中的最大值或最小值))
- [4.4 collection(把当前流转化为一个集合) ==最常用==](#4.4 collection(把当前流转化为一个集合) ==最常用==)
- [4.5 anyMatch(任一匹配)](#4.5 anyMatch(任一匹配))
- [4.6 allMatch(都符合条件)](#4.6 allMatch(都符合条件))
- [4.7 noneMatch(都不符合条件)](#4.7 noneMatch(都不符合条件))
- [4.8 findAny(获取任意一个元素)](#4.8 findAny(获取任意一个元素))
- [4.9 findFirst(获取流中的第一个元素)](#4.9 findFirst(获取流中的第一个元素))
一.概述
- 在 Java 中,Stream 是一个来自
java.util.stream
包的接口,用于对集合(如List、Set等)或数组等数据源进行操作的一种抽象层。它可以让你以一种声明式的方式处理数据,更专注于 "做什么" 而不是 "怎么做"。简单来说,Stream
就像是一条数据的管道,数据在这个管道中流动,并且可以在流动的过程中被各种操作修改。 - 对Stream流的操作可以分为三种:
- 创建流: 可以由数组或者集合创建.
- 中间操作: 每次返回一个新的流,可以有多个中间操作
- 终结操作: 每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合.
- Stream流的特性:
- 惰性求值(Lazy Evaluation):
Stream
流的中间操作(如filter、map、sorted
等)是惰性求值的。这意味着当你定义了一系列中间操作时,这些操作并不会立即执行。只有当遇到终端操作(如forEach、reduce、collect
等)时,整个操作链才会被触发执行。 - 不可变(Immutability): Stream 本身是不可变的。这意味着一旦一个 Stream 对象被创建,你不能修改它。每一个中间操作都会返回一个新的 Stream 对象,而不是在原始的 Stream 上进行修改。
- 管道化(Pipelining): Stream 操作可以像管道一样串联起来。一个操作的输出可以作为下一个操作的输入,从而可以对数据进行连续的处理。这种管道化的方式使得代码更加紧凑和易读,并且能够高效地处理数据。
- 内部迭代(Internal Iteration): 与传统的外部迭代(如使用for循环)不同,
Stream
采用内部迭代。在传统的外部迭代中,你需要手动控制迭代的过程,例如,在一个for循环中,你要明确地指定循环的起始、结束条件和每次迭代的步长。而在Stream
中,迭代的过程是由Stream
库内部管理的,你只需要指定要对数据进行什么操作(通过中间操作和终端操作)。 - 支持多种数据源和数据类型:
- 数据源多样性:Stream 可以从各种数据源创建,如集合(
List、Set、Map
等)、数组、I/O 通道等。这使得它可以广泛地应用于不同的数据处理场景。 - 数据类型多样性:它可以处理各种数据类型,包括基本数据类型(通过
IntStream、LongStream、DoubleStream
等专门的流)和引用数据类型。例如,可以创建一个IntStream
来处理整数数组,也可以创建一个Stream<String>
来处理字符串列表。
- 数据源多样性:Stream 可以从各种数据源创建,如集合(
- 惰性求值(Lazy Evaluation):
二.数据准备
java
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode//用于后期的去重使用
public class Author {
//id
private Long id;
//姓名
private String name;
//年龄
private Integer age;
//简介
private String intro;
//作品
private List<Book> books;
}
java
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode//用于后期的去重使用
public class Book {
//id
private Long id;
//书名
private String name;
//分类
private String category;
//评分
private Integer score;
//简介
private String intro;
}
java
private 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;
}
二.Stream流的创建
2.1 单列集合创建Stream流.
java
List<Author> authors = getAuthors();
Stream<Author> stream = authors.stream();
2.2 数组创建Stream流
Arrays.stream(数组)
或者使用Stream.of
来创建
java
Integer[] arr = {1,2,3,4,5};
Stream<Integer> stream = Arrays.stream(arr);
Stream<Integer> stream2 = Stream.of(arr);
2.3 双列集合创建Stream流
- 转换成单列集合后再创建
java
Map<String,Integer> map = new HashMap<>();
map.put("蜡笔小新",19);
map.put("黑子",17);
map.put("日向翔阳",16);
Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();
三. 中间操作.
3.1 filter(过滤操作)
- 可以对流中的元素进行条件过滤,符合过滤条件的才能继续留在流中。
- 打印所有姓名长度大于1的作家的姓名.
java
List<Author> authors = getAuthors();
authors.stream()
.filter(author -> author.getName().length()>1)
.forEach(author -> System.out.println(author.getName()));
3.2 map(计算或者转换)
打印所有作家的姓名
java
List<Author> authors = getAuthors();
authors
.stream()
.map(author -> author.getName())
.forEach(name->System.out.println(name));
3.3 distinct(去重操作)
- 打印所有作家的姓名,并且要求其中不能有重复元素。
java
List<Author> authors = getAuthors();
authors.stream()
.distinct()
.forEach(author -> System.out.println(author.getName()));
注意:distinct方法是依赖Object的equals方法来判断是否是相同对象的。所以需要注意重写equals方法。
3.4 sorted(排序操作)
- 对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素。
java
List<Author> authors = getAuthors();
// 对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素。
authors.stream()
.distinct()
.sorted((o1, o2) -> o2.getAge()-o1.getAge())
.forEach(author -> System.out.println(author.getAge()));
3.5 limit (设置流的长度)
- 对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素,然后打印其中年龄最大的两个作家的姓名。
java
List<Author> authors = getAuthors();
authors.stream()
.distinct()
.sorted()
.limit(2)
.forEach(author -> System.out.println(author.getName()));
3.6 skip(跳过前n个元素)
- 打印除了年龄最大的作家外的其他作家,要求不能有重复元素,并且按照年龄降序排序。
java
//打印除了年龄最大的作家外的其他作家,要求不能有重复元素,并且按照年龄降序排序。
List<Author> authors = getAuthors();
authors.stream()
.distinct()
.sorted()
.skip(1)
.forEach(author -> System.out.println(author.getName()));
3.7 flatMap(一个对象转为多个对象)
- 打印所有书籍的名字。要求对重复的元素进行去重。
java
// 打印所有书籍的名字。要求对重复的元素进行去重。
List<Author> authors = getAuthors();
authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.forEach(book -> System.out.println(book.getName()));
四.终结操作
4.1 forEach(遍历流中的每一个元素)
- 输出所有作家的名字
java
// 输出所有作家的名字
List<Author> authors = getAuthors();
authors.stream()
.map(author -> author.getName())
.distinct()
.forEach(name-> System.out.println(name));
4.2 count(获取流中元素的个数)
- 打印这些作家的所出书籍的数目,注意删除重复元素。
java
//打印这些作家的所出书籍的数目,注意删除重复元素。
List<Author> authors = getAuthors();
long count = authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.count();
System.out.println(count);
4.3 max和min(获取流中的最大值或最小值)
- 分别获取这些作家的所出书籍的最高分和最低分并打印。
java
// 分别获取这些作家的所出书籍的最高分和最低分并打印。
//Stream<Author> -> Stream<Book> ->Stream<Integer> ->求值
List<Author> authors = getAuthors();
Optional<Integer> max = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.max((score1, score2) -> score1 - score2);
Optional<Integer> min = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.min((score1, score2) -> score1 - score2);
System.out.println(max.get());
System.out.println(min.get());
4.4 collection(把当前流转化为一个集合) 最常用
- 获取一个存放所有作者名字的List集合。
java
// 获取一个存放所有作者名字的List集合。
List<Author> authors = getAuthors();
List<String> nameList = authors.stream()
.map(author -> author.getName())
.collect(Collectors.toList());
System.out.println(nameList);
- 获取一个所有书名的Set集合。
java
// 获取一个所有书名的Set集合。
List<Author> authors = getAuthors();
Set<Book> books = authors.stream()
.flatMap(author -> author.getBooks().stream())
.collect(Collectors.toSet());
System.out.println(books);
- 获取一个Map集合,map的key为作者名,value为List
java
// 获取一个Map集合,map的key为作者名,value为List<Book>
List<Author> authors = getAuthors();
Map<String, List<Book>> map = authors.stream()
.distinct()
.collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
System.out.println(map);
4.5 anyMatch(任一匹配)
- 判断是否有年龄在29以上的作家
java
// 判断是否有年龄在29以上的作家
List<Author> authors = getAuthors();
boolean flag = authors.stream()
.anyMatch(author -> author.getAge() > 29);
System.out.println(flag);
4.6 allMatch(都符合条件)
- 判断是否所有的作家都是成年人
java
// 判断是否所有的作家都是成年人
List<Author> authors = getAuthors();
boolean flag = authors.stream()
.allMatch(author -> author.getAge() >= 18);
System.out.println(flag);
4.7 noneMatch(都不符合条件)
- 判断作家是否都没有超过100岁的。
java
// 判断作家是否都没有超过100岁的。
List<Author> authors = getAuthors();
boolean b = authors.stream()
.noneMatch(author -> author.getAge() > 100);
System.out.println(b);
4.8 findAny(获取任意一个元素)
- 获取任意一个年龄大于18的作家,如果存在就输出他的名字
java
// 获取任意一个年龄大于18的作家,如果存在就输出他的名字
List<Author> authors = getAuthors();
Optional<Author> optionalAuthor = authors.stream()
.filter(author -> author.getAge()>18)
.findAny();
optionalAuthor.ifPresent(author -> System.out.println(author.getName()));
4.9 findFirst(获取流中的第一个元素)
- 获取流中的第一个元素。
java
// 获取一个年龄最小的作家,并输出他的姓名。
List<Author> authors = getAuthors();
Optional<Author> first = authors.stream()
.sorted((o1, o2) -> o1.getAge() - o2.getAge())
.findFirst();
first.ifPresent(author -> System.out.println(author.getName()));