0%

Java8新特性之集合流式编程

1.集合流的简介

1.1集合的流式编程简介

​ Stream是JDK1.8之后出来的新特性,也是JDK1.8中最值得学习的两种新特性之一。(另外一个是lambda表达式)

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

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

​ 集合的流式编程可以大幅度简化代码数量,将数据源中的数据读取到一个流中,可以对流中的数据进行删除、过滤、映射等多种操作,每次操作返回的结果也是一个流对象,可以对这个流对象再次进行操作

1.3 使用流式编程的步骤

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

  • 1、获取数据源,将数据源中的数据读取到流中
  • 2、对流中的数据进行各种处理
  • 3、对流中的数据整合处理

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

2.数据源的获取

2.1数据源的简介

数据源是流中的数据来源,是集合流式编程的第一步,将数据源中的数据读取到流中,进行处理。==注意:将数据读取到流中进行处理的时候,与数据源中的数据没有关系。就是说,中间操作对对流中的数据进行处理、过滤、映射、排序等,此时都不会影响数据源中的数据==

2.2数据源的获取

将集合容器中的数据读取到一个流中,无论什么容器作为数据源,读取到流中返回的都是一个Stream

1
2
3
4
5
6
//1.通过Collection接口中的stream()方法获取数据源为Collection的流
Stream<Integer> stream = list.stream();
//2.通过Collection接口的parallelStream()方法获取数据源为Collection的流
Stream<Integer> stream = list.parallelStream();
//3.通过Arrays工具类中的stream()方法获取数据源为数组的流
IntStream stream = Arrays.stream(array).collect(Collectors.toMap(e1 -> e1, o -> o * 10))

stream()和parallelStream的区别

stream()方法获取的数据源是串行的,parallelStream()获取的数据源是并行的。parallelStream()内部集成了多个线程对流中的数据进行操作,效率更高。

3.最终操作

3.1最终操作简介

将流中的数据整合到一起,存入一个集合,也可以直接对流中的数据进行遍历、数据统计等等,通过最终操作,需要掌握如何从流中提取我们想要的信息。

注意事项:之所以叫最终操作,是因为,在最终操作执行结束后,会关闭这个流,流中所有数据都会销毁。如果使用一个已经关闭了的流,会出现异常

3.2 collect

​ 将流中的数据收集到一起,对数据进行处理。最常见的处理是将流中的数据存入一个集合,collect方法的参数是一个Collector接口,而且不是一个函数式接口,实现这个接口,可以自定义收集规则。绝大部分情况,不需要自定义规则,直接使用Collectors工具类提供的方法即可。

1
2
3
4
5
6
7
//1.1转成List
List<Integer> result = list.stream().collect(Collectors.toList);
//1.2转成Set
Set<Integer> result1 = list.stream().collect(Collectors.toSet);//
//1.3转成Map,提供两个函数式接口实现,分别实现键的生产规则和值的生成规则
Map<Integer,Integer> result2 = list.stream().collect(Collectors.toMap(o1 -> o1, o2 -> o2*10))

3.3 reduce

​ 将流中的数据按照一定的规则聚合起来

1
2
3
//将流中的元素,逐一带入这个方法进行运算
//最终运算结果是一个Optional类型,需要通过get方法获取里面的数据
int result = list.stream().reduce(o1,o2->o1+o2).get();

3.4 count

​ 统计流中元素的数量

1
int result = list.stream().count();

3.5 foreach

​ 迭代,遍历

1
integerList.stream().forEach(System.out::println);

3.6 max & min

获取流中最大或者最小的元素

1
integerList.stream().max(Integer::compareTo).get();

3.7 Matching

1
2
3
4
5
6
7
8
9
//只有流中的所有元素都匹配指定的规则,才会返回true
boolean b = integerList.stream().allMatch(integer -> integer >= 1);
//只要流中的某个元素匹配指定的规则,就会返回true
boolean b1 = integerList.stream().anyMatch(integer -> integer >= 4);
//只有流中的所有元素都不匹配指定的规则,才会返回true
boolean b2 = integerList.stream().noneMatch(integer -> integer >= 4);
System.out.println(b);//true
System.out.println(b1);//false
System.out.println(b2);//true

3.8 find

1
2
3
4
5
6
7
8
9
10
List<Integer> integerList = new ArrayList<>();
Collections.addAll(integerList, 1, 2, 3);
//获取流中首元素
Integer integer = integerList.stream().findFirst().get();
//获取流中某个元素,一般情况获取首元素,多线程下返回不一定是首元素
Integer integer2 = integerList.stream().findAny().get();
Integer integer3 = integerList.parallelStream().findAny().get();
System.out.println(integer);//1
System.out.println(integer2);//1
System.out.println(integer3);//2

3.9 最终操作注意事项

​ 最终操作会关闭流,如果操作一个已经关闭了的流会报异常

1
2
3
4
5
6
7
8
9
//会出现异常 Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
List<Integer> integerList = new ArrayList<>();
Collections.addAll(integerList, 1, 2, 3);
Stream<Integer> stream = integerList.stream();
long count = stream.count();
System.out.println(count);
Integer integer = stream.max(Integer::compareTo).get();
System.out.println(integer);

4.0 InStream等基本数据类型的最终操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
        int[] ints = new int[]{1, 2, 3, 4, 5};
IntStream intStream = Arrays.stream(ints);
//常见的最终操作
// System.out.println("intStream.max() = " + intStream.max().getAsInt());//获取最大值
// System.out.println("intStream.min() = " + intStream.min().getAsInt());//获取最小值
// System.out.println("intStream.sum() = " + intStream.sum());//求和
// System.out.println("intStream.count() = " + intStream.count());//元素数量
//获取流的数据分析结果
IntSummaryStatistics intSummaryStatistics = intStream.summaryStatistics();
System.out.println(intSummaryStatistics.getMax());
System.out.println(intSummaryStatistics.getMin());
System.out.println(intSummaryStatistics.getSum());
System.out.println(intSummaryStatistics.getCount());
System.out.println(intSummaryStatistics.getAverage());

4. 中间操作

​ 对流中的数据进行各种操作、处理。中间操作可以是连续操作,每一次操作返回的都是一个Stream对象,可以继续进行其它操作,直到最终操作

4.1 filter

​ 条件过滤,仅保留满足条件的数据,其它不满足条件的数据会被删除

1
2
3
List<Integer> integerList = new ArrayList<>();
Collections.addAll(integerList, 1, 2, 3, 4, 5, 6);
integerList.stream().filter(integer -> integer > 5).forEach(System.out::println);//6

4.2 distinct

​ 去除集合中重复的元素,方法没有参数。去重规则和hashSet相同

1
2
3
4
5
6
7
8
List<Student> students = new ArrayList<>();
Collections.addAll(students,
new Student("zhangsan",16,90),
new Student("lisi",18,70),
new Student("zhaowu",17,98),
new Student("zhaowu",17,98)
);
students.stream().distinct().forEach(System.out::println);

4.3 sorted

​ 将流中的元素进行排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
    public static void sortedDataSource() {
List<Student> students = new ArrayList<>();
Collections.addAll(students,
new Student("zhangsan", 16, 90),
new Student("lisi", 18, 70),
new Student("zhaowu", 17, 98),
new Student("zhaowu", 17, 98)
);
//Student实现了Comparable接口,对流中的数据进行排序
// students.stream().distinct().sorted().forEach(System.out::println);
//对流中的数据按照自定义规则排序
students.stream().distinct().sorted((o1, o2) -> o1.score - o2.score).forEach(System.out::println);
}


@Data
static
class Student implements Comparable<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;
}

@Override
public int compareTo(Student o) {
return this.age - o.age;
}
}

4.4 limit & skip

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

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

1
2
3
4
5
6
//截取指定数量的元素
list.stream().limit(2).forEach(System.out::println);
//跳过开头指定数量的元素
list.stream().skip(2).forEach(System.out::println);
//配合使用,截取部分元素
list.stream().skip(2).limit(1).forEach(System.out::println);

4.5 map & flatMap

​ map: 对流中的数据进行映射,用新数据替换旧的数据

1
2
Stream<String> stream = students.stream().map(student -> String.valueOf(student.getAge()) + "岁");
System.out.println("stream.collect(Collectors.toList()) = " + stream.collect(Collectors.toList()));

​ flatMap是扁平化映射

1
2
//flatMap扁平化映射,常用于map映射完成后,流中的数据是一个个容器,而我们需要对容器中的数据进行处理,可以使用扁平化映射,将容器中的元素直接存入流中
students.stream().map(student -> student.getName().split("")).flatMap(Arrays::stream).distinct().forEach(System.out::println);

4.6 mapToInt,mapToLong等

​ 将流中的数据替换成Int类型,得到IntStream等对象,可以进行统计操作

1
2
IntStream intStream = students.stream().mapToInt(Student::getAge);
System.out.println("intStream.summaryStatistics().getAverage() = " + intStream.summaryStatistics().getAverage());

5. Collectors工具类

方法 描述
Collectors.toList() 将流中的数据聚合到一个List中
Collectors.toSet() 将流中的数据聚合到一个Set中
Collectors.toMap() 将流中的数据聚合到一个Map中
maxBy() 按照指定规则,找到流中最大元素,等同于max
minBy() 按照指定规则,找到流中最小元素,等同于min
joining() 将流中的数据拼接成一个字符串,注意:只能操作流中String的数据
summingInt() 将流中的数据,映射成int类型数据,并求和
averagingInt() 将流中的数据,映射成int类型数据,并求平均值
summarizingInt() 将流中的数据,映射成int类型数据,并获取描述信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//按照指定规则,找到流中最大元素,等同max
Student student = students.stream().collect(Collectors.maxBy((o1, o2) -> o1.getAge() - o2.getAge())).get();
System.out.println(student);
//将流中的数据拼接成一个字符串,注意:只能操作流中String的数据
String collect = students.stream().map(Student::getName).collect(Collectors.joining());
System.out.println(collect);
//将流中的数据,映射成int类型数据,并求和
Integer collect1 = students.stream().collect(Collectors.summingInt(Student::getAge));
System.out.println(collect1);
//将流中的数据,映射成int类型数据,并求平均值
Double collect2 = students.stream().collect(Collectors.averagingInt(Student::getAge));
System.out.println(collect2);
//将流中的数据,映射成int类型数据,并获取描述信息
IntSummaryStatistics collect3 = students.stream().collect(Collectors.summarizingInt(Student::getAge));
System.out.println(collect3.getMax());
-------------本文结束感谢您的阅读-------------