一、集合流的简介

1.1、集合流式编程的简介

Stream是JDK8后出现的新特性,也是JDK8中最值得学习的两种新特性之一(另一个是Lambda表达式)。

Stream是对集合操作的增强,流不是集合的元素,不是一种数据结构,不负责数据存储,流更像是一个迭代器,可以单向遍历一个集合中的每一个元素,并且不可循环。

1.2、为什么要使用集合流式编程?

有些时候,对集合中的元素进行操作的时候,需要使用到其他操作的结果,在这个过程中,集合的流式据程可以大幅度的简化代码的数量。将数据源中的数据,读取到一个流中,可以对这个流中的数据进行操作(删除、过滤,映射..…)。每次的操作结果也是一个流对象,可以对这个流再进行其他的操作。

1.3、使用步骤

通常情况下,对集合中的数据使用流式编程,需要经过以下三步:

  • 获取数据源,将数据源中的数据读取到流中
  • 对流中的数据进行各种各样的处理。
  • 对流中的数据进行整合处理。

​ 在上述三个过程中,过程2中,有若干方法,可以对流中的数据进行各种各样的操作,并且返回流对象本身,这样的操作,被称为中间操作,过程3中,有若干方法,可以对流中的数据进行各种处理,并关闭流,这样的操作,被称为最终操作

​ 在中间操作和最终操作中,基本上所有的方法参数都是函数式接口,可以使用lambda表达式来实现,使用集合的流式编程,来简化代码量,是需要对lambda表达式做到熟练掌握。

image-20210301194130742

二、数据源的获取

2.1、数据源简介

​ 数据源,顾名思义,既是流中的数据的来源。是集合的流式编程的第一步,将数据源中的数据读取到流中,进行处理。

​ 注意:将数据读取到流中进行处理的时候,与数据源中的数据没有关系。也就是说,中间操作对流中的数据进行处理、过滤、映射、排序..,此时是不会影响数据源中的数据的。

2.2、数据源获取

​ 这个过程,其实是将一个容器中的数据,读取到一个流中,因此无论什么容器作为数据源,读取到流中的方法返回值一定是一个Stream对象。

1、集合作为数据源

  • 调用集合对象stream()方法,这个方法会返回一个Stream对象。

这里以ArrayList对象为例

1
2
3
4
5
6
7
8
//1 实例化一个集合
List<Integer> list = new ArrayList<>();
//2 填充集合中的元素
Collections.addAll(list,0,1,2,3,4,5,6,7,8,9,10);
//3 读取集合中的元素,将其读取到流中
Stream<Integer> stream = list.stream();
//4 输出stream对象
System.out.println(stream);

运行程序,查看结果

image-20210301200137447

  • 调用集合对象parallelStream()方法,这个方法会返回一个Stream对象。

区别:stram()方法获取的是一个同步流,而parallelStream()方法返回一个并发流

2、数组作为数据源

  • 调用数据工具类 Arraysstream() 方法,传入转换为流对象的数组
1
2
3
4
5
6
//1 实例化一个数组
Integer[] arr = new Integer[]{0,1,2,3,4,5,6,7,8,9};
//2 读取数组中的数据到流中,得到一个流对象,使用Arrays工具类中的stream方法
Stream<Integer> stream = Arrays.stream(arr);
//3 输出得到的Stream对象
System.out.println(stream);

运行程序

image-20210301201154216

  • 将基本数据类型数组转换为流对象,同样调用数据工具类 Arraysstream() 方法,会根据传入数组的类型返回对应的流对象。

这里以int类型数组为例

1
2
3
4
5
6
//1 实例化一个数组
int[] arr = new int[]{0,1,2,3,4,5,6,7,8,9};
//2 读取数组中的数据到流中,得到一个流对象,使用Arrays工具类中的stream方法
IntStream stream = Arrays.stream(arr);
//3 输出得到的Stream对象
System.out.println(stream);

三、最终操作

首先编写一个getStream静态方法,这个方法用于将一个整数集合转换为一个Stream对象

1
2
3
4
5
6
7
public static Stream<Integer> getStream() {
//1 实例化一个集合
List<Integer> list = new ArrayList<>();
//2 填充集合中的元素
Collections.addAll(list,0,1,2,3,4,5,6,7,8,9,10);
return list.stream();
}

3.1、简介

​ 将流中的数据整合到一起,可以存入一个集合,也可以直接对流中的数据进行遍历、数据统计.…,通过最终操作,需要掌握如何从流中提取出来我们想要的信息。
​ 注意事项:最终操作,之所以叫最终操作,是因为,在最终操作执行结束后,会关闭这个流,流中的所有数据都会销毁,如果使用一个已经关闭了的流,会出现异常。

3.2、collect

将流中的数据收集到一起,对这些数据进行一些处理,最常见的处理,就是将流中的数据存入一个集合,collect方法的参数,是一个Collector接口,而且这个接口并不是一个函数式接口,实现这个接口,可以自定义收集的规则,但是,绝大部分情况下,不需要自定义。

​ 直接使用 Collectors 工具类提供的方法即可。

  • 将流中的数据转成List
1
2
3
4
List<Integer> list = new ArrayList<>();
Collections.addAll(list,0,1,2,3,4,5,6,7,8,9,10);
List<Integer> integerList = list.stream().collect(Collectors.toList());
System.out.println(integerList);

运行结果如下

image-20210301204010558

  • 将流中的数据转成一个Set
1
2
3
4
List<Integer> list = new ArrayList<>();
Collections.addAll(list,0,1,2,3,4,5,6,7,8,9,10);
Set<Integer> set = list.stream().collect(Collectors.toSet());
System.out.println(set);

运行结果如下

image-20210301204701061

  • 将流中的数据转换为一个Map,分别实现键的生成规则值的生成规则
1
2
3
4
List<Integer> list = new ArrayList<>();
Collections.addAll(list,0,1,2,3,4,5,6,7,8,9,10);
Map<String, Integer> map = list.stream().collect(Collectors.toMap(ele -> ele + "",ele -> ele));
System.out.println(map);

运行结果

image-20210301205023637

3.3、reduce

流中的数据以一定的规则聚合起来

reduce方法需要传入一个 BinaryOperator函数式接口对象,这个接口是BiFunction的子接口

image-20210301211315278

BinaryOperator 接口中,又对 BiFunction 中的泛型做了进一步限制,故 BinaryOperator 的apply方法中参数和返回值都是一个类型

image-20210301211548880

  • 使用reduce函数实现元素相加
1
2
3
4
5
//1 读取数据源,得到流对象
Stream<Integer> dataSource = getStream();
//2 最终操作
Integer sum = dataSource.reduce((p1, p2) -> p1 + p2).get();
System.out.println(sum);

上面代码的执行逻辑为:

将集合第一二个元素作为p1、p2,然后将得到的结果作为p1,第三个元素作为p2,再次执行函数,以此类推

image-20210301212459107

运行程序,查看结果

image-20210301212621194

3.4、count

统计流中的元素数量

1
2
long count = getStream().count();
System.out.println("流中数据个数为:" + count);

执行程序,查看结果

image-20210301213228442

3.5、foreach

foreach方法需要传入一个 Consumer函数接口对象,该接口中有一个accept抽象方法,accept方法接受一个参数且没有返回值

1
2
3
4
5
6
7
8
9
10
@FunctionalInterface
public interface Consumer<T> {

/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}

遍历流中的元素

1
2
3
getStream().forEach(ele -> {
System.out.println(ele);
});

配合方法引用,以上代码可以简化为:

1
getStream().forEach(System.out::println);

3.6、max&min

获取流中的最大元素、最小元素

Stream类中 max 和 min 方法源码如下

1
2
Optional<T> max(Comparator<? super T> comparator);
Optional<T> min(Comparator<? super T> comparator);

max 和 min 方法需要传入一个 Comparator 接口对象,该接口中有一个compare方法,用于自定义大小比较规则

1
2
3
4
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}

获取流中最大值最小值的代码如下,传入Integer类中的compareTo方法

1
2
3
4
Integer max = getStream().max(Integer::compareTo).get();
System.out.println("集合中最大的元素为:" + max);
Integer min = getStream().min(Integer::compareTo).get();
System.out.println("集合中最大的元素为:" + min);

Integer类中实现了Comparator方法,重写了compareTo方法

image-20210301215514697

1
2
3
4
5
6
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

运行程序,查看结果

image-20210301215320169

3.7、Matching

  • allMatch:只有当流中所有的元素,都匹配指定的规则时,才会返回true
1
2
boolean result = getStream().allMatch(ele -> ele > 50);
System.out.println("集合中是否所有数据都大于50?:" + result);

运行程序,查看结果

image-20210301220226746

  • anyMatch:只要流中有任意数据满足指定规则,就会返回true
1
2
boolean result = getStream().anyMatch(ele -> ele % 2 == 0);
System.out.println("集合中是否存在偶数?" + result);

运行程序,查看结果

image-20210301220436936

  • noneMatch:只有当流中的所有元素,都不满足指定的规则时,才会返回true
1
2
boolean result = getStream().noneMatch(ele -> ele > 50);
System.out.println("集合是否都小于50?" + result);

查看结果

image-20210301220837820

3.8、find

1、findFirst

从流中获取一个元素(获取开头的元素)

1
2
Integer integer = getStream().findFirst().get();
System.out.println("第一个元素为:" + integer);

运行程序,查看结果

image-20210301221400180

2、findAny

从流中获取一个元素(一般情况下,是获取的开头的元素)

1
2
Integer integer = getStream().findAny().get();
System.out.println("寻找的元素为:" + integer);

运行程序

image-20210301221502073

3、说明

​ 上面的两个方法,在绝大部分情况下,是完全相同的,但是在多线程的环境下,findFirstfindAny 返回的结果可能不一样。

findAny在并行流中获取的可能不是首元素

3.9、IntStream额外的最终操作

1、准备一个数组,转换为IntStream

1
2
3
public static IntStream getIntStream() {
return Arrays.stream(new int[]{1,2,3,4,5});
}

2、获取数据最大值

1
System.out.println(getIntStream().max().getAsInt());

3、获取数据最小值

1
System.out.println(getIntStream().min().getAsInt());

4、获取数组和

1
System.out.println(getIntStream().sum());

5、获取流中数据数量

1
System.out.println(getIntStream().count());

6、获取流中所有数据的平均值

1
System.out.println(getIntStream().average().getAsDouble());

7、获取到一个对流中数据的分析结果

1
IntSummaryStatistics statistics = getIntStream().summaryStatistics();
  • 获取最大值
1
System.out.println("最大值为:" + statistics.getMax());
  • 获取最小值
1
System.out.println("最小值为:" + statistics.getMin());
  • 获取数据和
1
System.out.println("和为:" + statistics.getSum());
  • 获取平均值
1
System.out.println("平均值为:" + statistics.getAverage());

3.10、注意事项

在执行完以上的最终操作后,流将会被关闭,流中所有数据都会被销毁,如果去操作一个已经关闭的流会抛出异常。

image-20210301210239525

四、中间操作

创建一个静态内部类Student,构造函数、Getter/Setter和toString省略不写

1
2
3
4
5
private static class Student {
private String name;
private int age;
private int score;
}

编写一个getDataSource方法,这个方法用于返回一个Stream对象

1
2
3
4
5
6
7
8
9
10
11
12
13
public static Stream<Student> getDataSource() {
ArrayList<Student> students = new ArrayList<>();
Collections.addAll(students,
new Student("wuhu1",18,98),
new Student("wuhu2",19,40),
new Student("wuhu3",21,50),
new Student("wuhu4",15,60),
new Student("wuhu5",12,92),
new Student("wuhu6",11,61),
new Student("wuhu7",19,96)
);
return students.stream();
}

4.1、简介

​ 将数据从数据源中读取到流中,中间操作,就是对流中的数据进行各种各样的操作、处理,中间操作可以连续操作,每一个操作的返回值都是一个Stream对象,可以继续进行其他操作,直到操作结束。

4.2、filter

条件过滤,仅保留满足指定条件的数据,其他不满足的数据都会被剔除

Stream类中 filter 方法如下,这个方法要求传入一个Predicate接口对象

1
Stream<T> filter(Predicate<? super T> predicate);

Predicate接口中的抽象方法如下

image-20210301230500980

1、过滤掉集合中成绩不及格的学生

筛选条件为 学生成绩 >= 60

1
2
Stream<Student> stream = getDataSource();
stream.filter(ele -> ele.score >= 60).forEach(System.out::println);

运行程序,查看结果

image-20210301231048054

2、过滤掉集合中未成年的学生

筛选条件为 学生年龄 >= 18

1
2
Stream<Student> stream = getDataSource();
stream.filter(ele -> ele.age >= 18).forEach(System.out::println);

运行程序

image-20210301231251567

4.3、distinct

去除集合中重复的元素,这个方法 没有 参数,去重的规则与HashSet相同。

先比较hashCode,如果hashCode结果相同,那么使用equals方法比较

  • 重写Student类中的equals和hashCode方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
score == student.score &&
name.equals(student.name);
}

@Override
public int hashCode() {
return Objects.hash(name, age, score);
}
  • 修改数据源,添加重复数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static Stream<Student> getDataSource() {
ArrayList<Student> students = new ArrayList<>();
Collections.addAll(students,
new Student("wuhu1",18,98),
new Student("wuhu2",19,40),
new Student("wuhu2",19,40),
new Student("wuhu3",21,50),
new Student("wuhu3",21,50),
new Student("wuhu4",15,60),
new Student("wuhu5",12,92),
new Student("wuhu5",12,92),
new Student("wuhu5",12,92),
new Student("wuhu6",11,61),
new Student("wuhu7",19,96)
);
return students.stream();
}
  • 使用Stream类中的distinct方法去重
1
2
Stream<Student> stream = getDataSource();
stream.distinct().forEach(System.out::println);
  • 运行程序,查看结果

image-20210301232416852

4.4、sorted

Stream类中有两个sorted方法,一个有参,一个无参

1
2
Stream<T> sorted();
Stream<T> sorted(Comparator<? super T> comparator);

1、有参sorted

有参 sorted 方法需要我们传入一个Comparator接口对象,我们需要自定义比较大小规则。

  • 在调用sorted时传入一个Comparator接口对象,自定义比较大小规则
1
2
Stream<Student> stream = getDataSource();
stream.sorted((s1,s2) -> s1.age - s2.age).forEach(System.out::println);
  • 查看结果

image-20210301233953340

2、无参sorted

将流中的数据,按照其对应的类实现的Comparable接口提供的比较规则进行排序。

  • 让Student类实现Comparable接口重写compareTo方法
1
2
3
4
5
6
private static class Student implements Comparable<Student>{
@Override
public int compareTo(Student student) {
return score - student.score;
}
}
  • 根据 Student 中 compareTo 方法定义的规则进行排序
1
2
Stream<Student> stream = getDataSource();
stream.sorted().forEach(System.out::println);
  • 查看结果

image-20210301233726676

4.5、limit & skip

limit :限制,截取流中指定数量的元素

skip:跳过,跳过流中指定数量的元素

1、limit

获取成绩前五名的学生信息

  • 修改学生类中的compareTo方法
1
2
3
4
@Override
public int compareTo(Student student) {
return student.score - score;
}
  • 代码如下
1
getDataSource().sorted().limit(5).forEach(System.out::println);
  • 查看结果

image-20210301234724840

2、skip

跳过集合中的前五个学生,从第六个学生开始打印

1
getDataSource().sorted().skip(5).forEach(System.out::println);

查看结果

image-20210301234956322

3、limit&skip

输出集合中成绩在第三-第七的学生信息,使用limit和skip

1
getDataSource().sorted().skip(2).limit(5).forEach(System.out::println);

运行,查看结果

image-20210301235129603

4.6、map&flatMap

1、map

map:提供一个映射规则,对流中的数据进行映射,用新的数据替换旧的数据

Stream类中map的源码如下

1
<R> Stream<R> map(Function<? super T, ? extends R> mapper);

其中Function接口是一个传入一个参数返回一个返回值的函数式接口

image-20210302121509802

实际需求:获取所有学生的名字

1
2
3
Stream<Student> stream = getDataSource();
List<String> stuNameList = stream.map(ele -> ele.getName()).collect(Collectors.toList());
stuNameList.stream().forEach(System.out::println);

运行程序,查看结果

image-20210302122007006

上面的代码也可以使用Student类中的方法引用来实现

1
2
3
Stream<Student> stream = getDataSource();
List<String> stuNameList = stream.map(Student::getName).collect(Collectors.toList());
stuNameList.stream().forEach(System.out::println);

2、flatMap

flatMap:扁平化映射,一般用于map映射后,流中的数据是一个容器,而我们需要对容器中的数据进行处理,此时我们可以使用扁平化映射,将容器中的数据直接读取到流中。

  • 模拟:统计字符串数组中所有出现的字符

思路如下:

  • 将字符串数组中的每一个字符串都切割为一个字符串数组
  • 将字符串数组中的数据进行扁平化映射
  • 对流中的字符串使用distinct进行去重
  • 打印
1
2
3
4
5
6
7
String[] array = {"Hello","World","Hehe"};
Stream<String> stringStream = Arrays.stream(array);
//统计字符串中所有出现的字符
stringStream.map(s -> s.split(""))
.flatMap(Arrays::stream)
.distinct()
.forEach(System.out::println);
  • 运行程序,查看结果

image-20210302124010884

五、Collectors工具类

5.1、概念

Collectors 是一个工具类,里面封装了很多方法,可以很方便的获取到一个Collector接口的实现类对象,从而可以使用collect方法,对流中的数据进行各种各样的处理和整合

5.2、常用方法

方法描述
Collectors.toList()将流中的数据,整合到一个 List 集合中
Collectors.toSet()将流中的数据,整合到一个 Set 集合中
Collectors.toMap()将流中的数据,整合到一个 Map 集合中
maxBy()按照指定的规则,找到流中最大的元素,等同与 max
minBy()按照指定的规则,找到流中最小的元素,等同与 min
joining()将流中的数据拼接为一个字符串,注意:只能操作流中是 String 的数据
summingInt()将流中的数据映射成 int 类型的数据,并求和
averagingInt()将流中的数据映射成 int 类型的数据,并求平均值
summarizingInt()将流中的数据映射成 int 类型的数据,并获取描述信息

5.3、示例代码

1、joining

  • 拼接字符串数组中的所有字符串
1
2
3
4
5
6
7
//1 准备一个字符串数组,作为数据源
String[] dataSource = {"wuhu","qifei","java"};
//2 将数组中的数据转换为流对象
Stream<String> stream = Arrays.stream(dataSource);
//3 使用joining将流中的数据拼接为一个字符串
String collect = stream.collect(Collectors.joining());
System.out.println("拼接之后的结果为:" + collect);

运行程序,查看结果

image-20210302134641765

重载方法一

  • 传入一个分隔符,令拼接而成的字符串根据传入的分隔符分割开来,格式为:

字符串 分隔符 字符串2分隔符 字符串3 …

  • 传入一个分隔符、一个前缀和一个尾缀,拼接而成的结果字符串格式为

“前缀” 字符串 分隔符 字符串2分隔符 字符串3 … “后缀”

  • 传入分隔符的joining
1
2
3
4
5
6
7
//1 准备一个字符串数组,作为数据源
String[] dataSource = {"wuhu","qifei","java"};
//2 将数组中的数据转换为流对象
Stream<String> stream = Arrays.stream(dataSource);
//3 使用joining将流中的数据拼接为一个字符串
String collect = stream.collect(Collectors.joining(","));
System.out.println("拼接之后的结果为:" + collect);

运行程序,查看结果

image-20210302135340206

  • 传入分隔符、前缀和尾缀的joining
1
2
3
4
5
6
7
//1 准备一个字符串数组,作为数据源
String[] dataSource = {"wuhu","qifei","java"};
//2 将数组中的数据转换为流对象
Stream<String> stream = Arrays.stream(dataSource);
//3 使用joining将流中的数据拼接为一个字符串
String collect = stream.collect(Collectors.joining(", ","[","]"));
System.out.println("拼接之后的结果为:" + collect);

结果

image-20210302135439927

2、summingInt

Collectors 中 summingInt 方法的源码如下

image-20210302135726430

summingInt方法需要传入一个ToIntFunction接口对象 ,这个接口的抽象方法将一个对象转换为int类型数据

1
2
3
4
@FunctionalInterface
public interface ToIntFunction<T> {
int applyAsInt(T value);
}
  • 输出字符串数组中的字符串总长度
1
2
3
4
5
6
7
//1 准备一个字符串数组,作为数据源
String[] dataSource = {"wuhu","qifei","java"};
//2 将数组中的数据转换为流对象
Stream<String> stream = Arrays.stream(dataSource);
//使用summingInt方法,输出字符串数组的总长度
Integer sumLength = stream.collect(Collectors.summingInt(ele -> ele.length()));
System.out.println("数组中字符串总长度为:" + sumLength);

结果

image-20210302140113830

六、综合案例

一个集合中存储了若干个学生对象,要求编码实现以下功能

其中,学生类的属性如下

1
2
3
4
5
6
7
8
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private String name;
private Integer age;
private Integer score;
}

数据源如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static Stream<Student> getStream() {
List<Student> students = new ArrayList<>();
Collections.addAll(students,
new Student("芜湖1",18,90),
new Student("芜湖2",15,60),
new Student("芜湖3",12,70),
new Student("芜湖4",11,65),
new Student("芜湖5",19,85),
new Student("芜湖6",20,40),
new Student("芜湖7",25,30),
new Student("芜湖8",30,99),
new Student("芜湖9",18,100),
new Student("芜湖10",18,20),
new Student("芜湖11",18,45),
new Student("芜湖12",18,55)
);
return students.stream();
}

6.1、所有及格的学生信息

使用中间操作 filter ,筛选条件为学生成绩 >= 60

1
2
Stream<Student> stream = getStream();
stream.filter(ele -> ele.getScore() >= 60).forEach(System.out::println);

结果

image-20210302142208348

6.2、所有及格的学生姓名

使用中间操作 filtermap ,其中筛选条件为 学生成绩>=60 ,在筛选完及格的学生后,需要使用 map 将学生对象映射为 学生姓名

1
2
Stream<Student> stream = getStream();
stream.filter(ele -> ele.getScore() >= 60).map(Student::getName).forEach(System.out::println);

结果

image-20210302142450138

6.3、所有学生的平均成绩

用到流对象 mapToInt 方法,这个方法将Stream对象转换为一个IntStream对象,再调用 IntStream 对象的 averagegetAsDouble 方法即可。

1
2
3
Stream<Student> stream = getStream();
double avgScore = stream.mapToInt(Student::getScore).average().getAsDouble();
System.out.println("所有学生的平均成绩为:" + avgScore);

结果

image-20210302143236123

6.4、班级的前三名

先使用Stream对象的 sorted 方法排序,然后使用 limit 取前三条即可。

1
2
Stream<Student> studentStream = getStream();
studentStream.sorted((s1,s2) -> s2.getScore() - s1.getScore()).limit(3).forEach(System.out::println);

结果

image-20210302143522931

6.5、班级的3-10名

先使用Stream对象的 sorted 方法排序,然后使用 skip 跳过前三条,再用limit取后面七条即可

1
2
Stream<Student> studentStream = getStream();
studentStream.sorted((s1,s2) -> s2.getScore() - s1.getScore()).skip(3).limit(7).forEach(System.out::println);

结果

image-20210302143727979

6.6、所有不及格学生的平均成绩

先使用 filter 筛选所有不及格学生,然后使用 mapToInt 将流对象转换为IntStream流对象,最后调用IntStream流对象的 averagegetAsDouble 方法即可。

1
2
3
Stream<Student> stream = getStream();
double avgScore = stream.filter(ele -> ele.getScore() < 60).mapToInt(Student::getScore).average().getAsDouble();
System.out.println("所有不及格学生的平均成绩为:" + avgScore);

结果

image-20210302143956708

6.7、将及格的学生,按照降序顺序输出所有信息

先使用 filter 筛选所有及格学生,然后使用sorted 进行排序,再输出所有及格学生信息即可

1
2
Stream<Student> stream = getStream();
stream.filter(ele -> ele.getScore() >= 60).sorted((s1,s2) -> s2.getScore() - s1.getScore()).forEach(System.out::println);

结果

image-20210302144148021

6.8、班级学生的总分

使用流对象的 mapTo 方法,将流对象转换为IntStream对象,然后调用sum 方法即可。

1
2
3
Stream<Student> stream = getStream();
int sum = stream.mapToInt(Student::getScore).sum();
System.out.println("班级所有学生总成绩为:" + sum);

结果如下

image-20210302144349019