一.了解stream流
1.1stream的概念
- Stream流(也叫Stream API)。它是从JDK8以后才有的一个新特性,是专业用于对集合或者数组进行便捷操作的。
- Java Stream可以看作是对数据集合的一种高级封装,它将数据集合的操作抽象出来,允许我们以声明式的方式进行数据处理。与传统的集合操作相比,Java Stream更加灵活、可读性更强,并且可以充分利用多核处理器来进行并行处理。
2.2 Stream的特点和优势
- 声明式编程:使用Stream时,可以将数据处理过程描述为一系列转换操作,使代码更加简洁易读。
- 内部迭代:Stream处理数据时,无需显式使用迭代器,而是通过内部迭代器来进行遍历操作。
- 惰性求值:Stream提供了惰性求值的特性,只有当需要获取结果时才会进行实际的计算,可以减少不必要的计算开销。
- 并行处理:Stream可以利用多核处理器来进行并行处理,提高数据处理的效率。
- Java Stream提供了丰富的操作方法,包括过滤、映射、排序、去重、聚合等,可以对数据进行各种复杂的处理。
二.Stream流基本语法与常用的API
2.1Stream流中间方法
中间方法指的是:调用完方法之后其结果是一个新的Stream流,于是可以继续调用方法,这样一来就可以支持链式编程(或者叫流式编程)。
2.2Stream流终结方法
这些方法的特点是,调用完方法之后,其结果就不再是Stream流了,所以不支持链式编程。
2.3基本使用
接下里我们通过案例来体验一下有多方便
案例需求:有一个List集合,元素有"张三丰","张无忌","周芷若","赵敏","张强"
,找出姓张,且是3个字的名字,存入到一个新集合中去。
List<String> names = new ArrayList<>();
Collections.addAll(names, "张三丰","张无忌","周芷若","赵敏","张强");
System.out.println(names);
- 用传统方式来做,代码是这样的
// 找出姓张,且是3个字的名字,存入到一个新集合中去。
List<String> list = new ArrayList<>();
for (String name : names) {
if(name.startsWith("张") && name.length() == 3){
list.add(name);
}
}
System.out.println(list);
- 用Stream流来做,代码是这样的(想流水线一样,一句话就写完了)
List<String> list2 = names.stream().filter(s -> s.startsWith("张")).filter(a -> a.length()==3).collect(Collectors.toList());
System.out.println(list2);
三.Java Stream流的工作流程
Java Stream 流的工作流程可以概括为以下几个步骤:
- 创建数据源:首先,你需要有一个数据源,如集合或数组。通过调用
Collection.stream()
方法或Arrays.stream()
方法,你可以将数据源转换为相应的流对象。 - 中间操作:一旦有了流对象,你可以对其进行一系列的中间操作。中间操作是指对数据进行过滤、映射、排序等操作,每个中间操作都会返回一个新的流。例如,你可以使用
.filter()
方法过滤掉不符合条件的数据,使用.map()
方法对数据进行转换,使用.sorted()
方法对数据进行排序等。 - 终止操作:在完成中间操作后,你可以进行终止操作来触发流的计算。终止操作是最后的操作,它会产生最终的结果或副作用。常见的终止操作包括使用
.forEach()
方法迭代流中的每个元素,使用.collect()
方法将流的元素收集到一个集合中,使用.reduce()
方法对流的元素进行归约等。 - 惰性求值和内部迭代:Stream 流的操作是惰性求值的,中间操作不会立即执行,而是等到终止操作时才进行计算。另外,Stream 流使用内部迭代来处理数据,这意味着你不需要手动编写迭代逻辑,而是将数据处理的工作交给了 Stream 内部来完成。
- 并行流处理:Stream 流提供了并行流(Parallel Stream)的支持,可以通过
.parallel()
方法将流转换为并行流,从而实现并行处理。并行流利用多线程来加速数据处理,适用于处理大量数据或需要并行计算的场景。
四.了解 Java Stream 流的原理
4.1为什么可以链式调用
返回自身:Stream 中的中间方法一般都会返回一个新的 Stream 对象,这个新的 Stream 对象可以继续调用其他方法。这种设计使得我们可以将多个方法调用连接在一起,形成一条连续的操作流水线。链式编程的特点是每个方法的返回值都是当前对象,这样就可以串联多个方法调用
4.2Stream 接口:
Java Stream 的定义位于 java.util.stream.Stream
接口中。它是一个泛型接口,提供了用于操作数据流的各种方法。
4.2数据源和中间操作
Stream 是由一个数据源(如集合、数组等)和一系列中间操作组成的。中间操作包括 filter、map、flatMap、distinct、sorted、limit 等。这些中间操作可以通过调用 Stream 对象上的方法来进行链式调用。
4.3惰性求值
Stream 使用惰性求值的方式来处理数据。这意味着在执行中间操作时,并不会立即计算,而是将操作的逻辑保存起来。只有当执行终止操作(如 collect、forEach、count 等)时,才会触发实际的计算。
4.4StreamSpliterators
StreamSpliterators 是 Stream 中数据的生成器,它负责维护源数据的状态和分割数据流。流水线中的中间操作通常会涉及到 StreamSpliterators 进行数据处理和分割。
4.5Spliterator 接口
Spliterator 是一个用于遍历和分割数据源的接口,StreamSpliterators 实现了 Spliterator 接口。Spliterator 定义了一些方法,如 tryAdvance、forEachRemaining、trySplit 等,用于实现数据的遍历和分割。
4.6TerminalSink
TerminalSink 是 Stream 流的终止操作的实现,它接收 Stream 中的元素并生成最终的结果。TerminalSink 是一个 Sink 接口的实现类。