如何使用Java中的Stream函数来处理函数式编程?
Stream是Java 8中的一项新特性,它是对集合进行函数式编程的一种方式。它可以在不改变源集合的情况下进行并行化和延迟计算。Stream基于函数式编程的思想,如map、reduce等,让我们通过一段优雅的代码来处理集合数据,使之易于理解和维护。在这篇文章中,我们将介绍如何使用Java中的Stream函数来处理函数式编程。
一、Stream的基本概念
Stream是一个数据交互的管道,它的两端分别是输入端和输出端。Stream可以对输入端的数据进行一系列操作,最终输出到输出端,这个过程就称为流水线处理。
Stream分为中间操作和终止操作,中间操作可以链式调用,而终止操作只能执行一次。
二、Stream操作分类
Stream的操作分为三类:
1、Intermediate Ops(中间操作)
Intermediate Ops是对数据流的中间操作,这些操作会对数据流进行操作并返回一个新的Stream。
常用的中间操作:
?filter(Predicate<? super T> predicate):过滤数据
?map(Function<? super T, ? extends R> mapper):将一个类型的数据转换成另一个类型
?flatMap(Function<? super T, ? extends Stream<? extends R>> mapper):将一个类型的数据转换成一个Stream
?distinct():去重
?sorted():排序
2、Terminal Ops(终止操作)
Terminal Ops是最后的操作,它会返回一个结果或一个副作用。这个操作只能进行一次,因为它会关闭Stream。终止操作是有返回值的,例如count()返回一个long类型的值。
常用的中间操作:
?forEach(Consumer<? super T> action):对数据流中的每个元素执行 action 操作。
?toArray():将数据流转换成数组返回
?reduce(T identity, BinaryOperator<T> accumulator):对数据流中的所有元素按 BinaryOperator 进行归约,得到一个值。
?count():计算数据流中的元素数量。
?collect(Collector<? super T, A, R> collector):将数据流转换成集合
3、Stateful Intermediate Ops(有状态中间操作)
Stateful Intermediate Ops是需要状态来执行的操作,它们需要知道之前的元素是什么,才能正确地操作。
常用的中间操作:
?peek(Consumer<? super T> action):查看元素
?limit(long maxSize):限制数据流元素的数量
?skip(long n):跳过前 n 个元素
三、Stream实战
下面来将基于学生成绩数据,展示如何使用Stream函数来处理函数式编程。
首先,我们创建一个Student类,用于存储学生信息:
public class Student {
private String name;
private int age;
private int score;
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
// getter and setter methods
}
现在我们创建一个包含10个学生信息的列表。
List<Student> studentList = Arrays.asList(
new Student("张三", 18, 88),
new Student("李四", 25, 70),
new Student("王五", 20, 95),
new Student("赵六", 28, 78),
new Student("钱七", 22, 64),
new Student("郑八", 21, 82),
new Student("孙九", 24, 90),
new Student("周十", 23, 94),
new Student("吴十一", 27, 75),
new Student("郭十二", 26, 85)
);
1. 按照分数排序并输出
我们可以使用Stream的sorted()方法来排序,然后使用forEach()方法来输出每个学生信息。
studentList.stream()
.sorted(Comparator.comparing(Student::getScore))
.forEach(student -> System.out.println(student.getName() + " " + student.getAge() + " " + student.getScore()));
输出结果为:
钱七 22 64
李四 25 70
吴十一 27 75
赵六 28 78
郑八 21 82
张三 18 88
郭十二 26 85
孙九 24 90
周十 23 94
王五 20 95
2. 输出总分数
我们将使用mapToInt()方法将每个学生的分数映射到一个IntStream中,然后使用sum()方法来计算总分数。
int totalScore = studentList.stream()
.mapToInt(Student::getScore)
.sum();
System.out.println("学生总分数:" + totalScore);
输出结果为:
学生总分数:812
3. 输出平均分数
我们将使用mapToInt()方法将每个学生的分数映射到一个IntStream中,然后使用average()方法来计算平均分数。
OptionalDouble averageScore = studentList.stream()
.mapToInt(Student::getScore)
.average();
System.out.println("学生平均分数:" + averageScore.getAsDouble());
输出结果为:
学生平均分数:81.2
4. 描述最高分数
我们可以使用max()方法来查找最高的学生成绩,然后使用ifPresent()方法来检查结果是否为空。
studentList.stream()
.max(Comparator.comparing(Student::getScore))
.ifPresent(student -> System.out.println("最高分数为:" + student.getScore()));
输出结果为:
最高分数为:95
5. 过滤及计数
我们将使用filter()方法来过滤数据,并使用count()方法来统计数据。
long count = studentList.stream()
.filter(student -> student.getScore() > 80)
.count();
System.out.println("80分以上学生人数有:" + count + "个");
输出结果为:
80分以上学生人数有:7个
四、总结
使用Stream函数来处理函数式编程能够简化代码,改进代码可读性和维护性。然而,这不是一个万能的技术,只用在满足以下两个条件时,才使用Stream函数:
1、数据源需要是集合或数组
2、数据需要执行一系列处理和计算
因为Stream函数的处理需要重心放在处理数据而不是语法上。因此,在代码可读性和代码保护性方面完全不如面向对象编程。
