函数式编程入门:用 Stream 流简化数据处理

👋 前言

简介

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);

🎉 欢迎关注我的公众号

微信公众号

  • 16
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值