👋 前言
简介
Stream流是Java 8中引入的一种新的API !importance重要 它主要是用于对集合数据进行处理的工具。Stream流可以用于对集合进行过滤、排序、映射、归约等操作,这些操作可以通过链式调用来完成,使得代码更加简洁和易于阅读。Stream流还支持并行处理,可以帮助我们更快地处理大量数据。
特点
stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果
stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。
💡 正文
1 创建流
1.1 集合创建
我们可以通过调用集合的 stream() 方法来创建一个 Stream 对象
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = numbers.stream();
1.2 数组创建
Java 8 引入了 Arrays 类的 stream() 方法,我们可以使用它来创建一个 Stream 对象
String[] names = {"Alice", "Bob", "Carol"};
Stream<String> stream = Arrays.stream(names);
1.3 通过 Stream.of() 创建
我们可以使用 Stream.of() 方法直接将一组元素转换为 Stream 对象
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
1.4 Collection集合创建
应用中最常用的一种
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Stream<Integer> stream = list.stream();
1.5 Stream.builder()
如果我们不确定要添加多少个元素到 Stream 中,可以使用 Stream.builder() 创建一个 Stream.Builder 对象,并使用其 add() 方法来逐个添加元素,最后调用 build() 方法生成 Stream 对象
Stream.Builder<String> builder = Stream.builder();
builder.add("Apple");
builder.add("Banana");
builder.add("Cherry");
Stream<String> stream = builder.build();
1.6 其他方式,不常用
I/O 资源创建,Stream.generate() 方法, Stream.iterate() 方法
操作符
流的操作类型主要分为两种:中间操作符、终端操作符
2.1 中间操作符
基础示例代码:
@Data
@AllArgsConstructor
@Builder
public class Student {
/**
* 学号
*/
private Integer sid;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 班级
*/
private String classes;
}
public class StreamTest {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student(1, "张三", 20, "1班"));
students.add(new Student(2, "李四", 18, "1班"));
students.add(new Student(3, "王五", 24, "1班"));
students.add(new Student(4, "赵六", 19, "2班"));
students.add(new Student(5, "钱七", 28, "2班"));
students.add(new Student(6, "韩八", 36, "3班"));
students.add(new Student(7, "赵九", 30, "3班"));
}
}
2.1.1 filter
用于通过设置的条件过滤出元素
// 获取年龄大于25的学生信息
students.stream()
.filter(student -> student.getAge() > 25)
.forEach(System.out::println);
// 结果
// Student(sid=5, name=钱七, age=28, classes=2班)
// Student(sid=6, name=韩八, age=36, classes=3班)
// Student(sid=7, name=赵九, age=30, classes=3班)
2.1.2 map
接受一个函数作为参数。这个函数会被应用到每个元素上,并将其映射成一个新的元素(使用映射一词,是因为它和转换类似,但其中的细微差别在于它是“创建一个新版本”而不是去“修改”)
// 按照姓名:xx,年龄:xx的格式打印学生信息
students.stream()
.map(student -> "姓名:" + student.getName() + ", 年龄:" + student.getAge())
.forEach(System.out::println);
// 结果
// 姓名:张三, 年龄:20
// 姓名:李四, 年龄:18
// 姓名:王五, 年龄:24
// 姓名:赵六, 年龄:19
// 姓名:钱七, 年龄:28
// 姓名:韩八, 年龄:36
// 姓名:赵九, 年龄:30
2.1.3 distinct
返回一个元素各异(根据流所生成元素的hashCode和equals方法实现)的流
// 输出班级信息,并进行去重操作
students.stream()
.map(Student::getClasses)
.distinct()
.forEach(System.out::println);
// 结果
// 1班
// 2班
// 3班
2.1.4 sorted
返回排序后的流
// 根据年龄升序排序
students.stream()
.sorted(Comparator.comparing(Student::getAge).reversed())
.forEach(System.out::println);
// 结果
// Student(sid=6, name=韩八, age=36, classes=3班)
// Student(sid=7, name=赵九, age=30, classes=3班)
// Student(sid=5, name=钱七, age=28, classes=2班)
// Student(sid=3, name=王五, age=24, classes=1班)
// Student(sid=1, name=张三, age=20, classes=1班)
// Student(sid=4, name=赵六, age=19, classes=2班)
// Student(sid=2, name=李四, age=18, classes=1班)
2.1.5 limit
会返回一个不超过给定长度的流
// 获取年龄最小的三个人信息
students.stream()
.sorted(Comparator.comparing(Student::getAge))
.limit(3)
.forEach(System.out::println);
// 结果
// Student(sid=2, name=李四, age=18, classes=1班)
// Student(sid=4, name=赵六, age=19, classes=2班)
// Student(sid=1, name=张三, age=20, classes=1班)
2.1.6 skip
返回一个扔掉了前n个元素的流
// 跳过5条数据获取后面的数据
students.stream()
.skip(5)
.forEach(System.out::println);
// 结果
// Student(sid=6, name=韩八, age=36, classes=3班)
// Student(sid=7, name=赵九, age=30, classes=3班)
2.1.7 flatMap
map:对流中每一个元素进行处理
flatMap:流扁平化,让你把一个流中的“每个值”都换成另一个流,然后把所有的流连接起来成为一个流
总结:map是对一级元素进行操作,flatmap是对二级元素操作
// 将两个一维数组转二维数组并输出
List<Integer> numbers1 = Arrays.asList(1, 2, 3);
List<Integer> numbers2 = Arrays.asList(3, 4);
// flatMap升维度
numbers1.stream()
.flatMap(x -> numbers2.stream().map(y -> new int[]{x, y}))
.forEach(s -> System.out.println(Arrays.toString(s)));
// 结果
// [1, 3]
// [1, 4]
// [2, 3]
// [2, 4]
// [3, 3]
// [3, 4]
2.1.8 peek
对元素进行遍历处理
// 对元素进行遍历处理,每个学生加上年级
students.stream()
.peek(student -> student.setClasses("5年" + student.getClasses()))
.forEach(System.out::println);
// 结果
// Student(sid=1, name=张三, age=20, classes=5年1班)
// Student(sid=2, name=李四, age=18, classes=5年1班)
// Student(sid=3, name=王五, age=24, classes=5年1班)
// Student(sid=4, name=赵六, age=19, classes=5年2班)
// Student(sid=5, name=钱七, age=28, classes=5年2班)
// Student(sid=6, name=韩八, age=36, classes=5年3班)
// Student(sid=7, name=赵九, age=30, classes=5年3班)
2.2 终端操作符
流方法 | 含义 |
---|---|
collect | 收集器,将流转换为其他形式 |
forEach | 遍历流 |
findFirst | 返回第一个元素 |
findAny | 将返回当前流中的任意元素 |
count | 返回流中元素总数 |
sum | 求和 |
max | 最大值 |
min | 最小值 |
anyMatch | 检查是否至少匹配一个元素,返回boolean |
allMatch | 检查是否匹配所有元素,返回boolean |
noneMatch | 检查是否没有匹配所有元素,返回boolean |
reduce | 可以将流中元素反复结合起来,得到一个值 |
2.2.1 collect
收集器,将流转换为其他形式
// 将流转换成list和set
List<Student> list = students.stream().collect(Collectors.toList());
Set<Student> set = students.stream().collect(Collectors.toSet());
2.2.2 forEach
遍历流
// 遍历输出
students.stream().forEach(System.out::println);
2.2.3 findFirst
返回第一个元素
// 获取第一个元素
Student stu = students.stream().findFirst().get();
System.out.println(stu);
2.2.4 findAny
将返回当前流中的任意元素
// 返回任意元素
Student stu = students.stream().findAny().get();
System.out.println(stu);
2.2.5 count
// 获取年龄大于25岁的总数
long count = students.stream().filter(student -> student.getAge() > 25).count();
System.out.println(count);
2.2.6 sum
求和
// 获取年龄总和
int sum = students.stream().mapToInt(Student::getAge).sum();
System.out.println(sum);
2.2.7 max
最大值
// 获取年龄最大的人的姓名
String name = students.stream().max(Comparator.comparing(Student::getAge)).get().getName();
System.out.println(name);
2.2.8 min
最小值
// 获取年龄最小的人的姓名
String name = students.stream().min(Comparator.comparing(Student::getAge)).get().getName();
System.out.println(name);
2.2.9 anyMatch
检查是否至少匹配一个元素,返回boolean
// 检查姓名为张三的是否存在
boolean b = students.stream().anyMatch(student -> student.getName().equals("张三"));
System.out.println(b);
2.2.10 allMatch
检查是否匹配所有元素,返回boolean
// 检查所有人是否都叫张三
boolean b = students.stream().allMatch(student -> student.getName().equals("张三"));
System.out.println(b);
2.2.11 noneMatch
检查是否没有匹配所有元素,返回boolean
// 检查没有人叫韩梅梅的人
boolean b = students.stream().noneMatch(student -> student.getName().equals("韩梅梅"));
System.out.println(b);
2.2.12 reduce
可以将流中元素反复结合起来,得到一个值
// 计算1-9的和
Integer num = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).reduce(0, (n1, n2) -> n1 + n2);
System.out.println(num);