概念及其特征
- Java的Stream流是在Java 8中引入的一种用于处理集合数据的功能强大且易于使用的工具,旨在简化集合框架的操作。它的设计目的是为了提供一种更简洁、更灵活和更可读的方式来处理集合数据。
- Stream流是对集合进行操作的高级抽象,可以将集合看作是一种源(source),而Stream表示这个源上进行的计算操作序列。 通过使用Stream API,我们可以以流水线方式处理数据,并进行各种转换和聚合操作。
- Java中有两种流:流(Stream)表示顺序流,按照数据源的顺序进行操作,适用于串行操作;并行流(ParallelStream),可以同时对数据源的多个元素进行操作,适用于并行计算。
流式编程具有以下特点:
- 流是一次性的:流不会保存元素,它仅仅描述了操作的序列,并且在执行聚合操作之后就被消耗掉了。即使我们对一个流执行多个操作,每个操作也只会在需要输出结果时才会执行,并且在执行完毕后,流不能再次使用。这与传统的集合不同,集合可以随时进行增删元素的操作;
- 流是无状态的:流的操作不会修改原始数据结构,而是通过创建一个新的流来执行操作,并最终返回一个结果。原始数据结构保持不变,这种无状态的特性使得流操作可以并行处理数据,不用担心多线程下的数据竞争问题;
- 流是延迟执行的:流的操作被称为延迟执行,也就是说,在流的聚合操作被触发之前,中间操作不会立即执行。这意味着我们可以先构建一个复杂的流操作链,然后在需要结果的时候才触发最终的操作。这种延迟执行的机制有助于优化性能,避免不必要
Stream流的实现原理主要基于迭代器和函数式编程的思想。在内部迭代的过程中,流通过一系列操作进行链式处理,将每个元素传递给下一个操作,并最终生成结果。
在并行流的情况下,流将输入数据分成多个小块,分配给不同的线程并行处理。处理完后,再合并结果并返回。
使用语法
Stream提供了两种类型的操作——中间操作和终端操作。中间操作用于链式调用,并可以有多个,而终端操作是触发计算的地方。使用Stream主要分为三个步骤:
- 创建流:也即获取一个Stream对象,可以通过集合、数组或者其他方式创建一个Stream。如可以使用
Stream.of()
方法创建流; - 进行中间操作:对Stream进行连续的中间操作,包括过滤、映射、排序、去重等处理。如可以使用
forEach()
方法遍历流中的元素,并使用filter()
、map()
、sorted()
等方法对流进行操作; - 执行终结操作:最后使用一个终结操作来触发计算并产生结果,如收集、聚合、遍历等。如可以使用
reduce()
方法进行元素的归约操作,使用collect()
方法进行元素的收集操作。
常用的操作:
- 去重(distinct): list = list.stream().distinct().collect(Collectors.toList())。底层原理是通过将 List类型 转换为 LinkedSet类型后,根据equals()方法和对象的hashCode()去重 的方式去重。
示例1:根据List集合对象的name属性进行去重:
方法一核心代码:list = list.stream().filter(o -> o.getName() != null).collect(
Collectors.collectingAndThen(Collectors.toCollection(
() -> new TreeSet<>(Comparator.comparing(o -> o.getName()))), ArrayList<Aoo>::new));
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Collectors;
public class Test {
public static void main(String[] args) {
List<Aoo> list = Arrays.asList(new Aoo("a.name"), new Aoo("b.name"), new Aoo("c.name"));
System.out.println("list before operate : " + list);
list = list.stream().filter(o -> o.getName() != null).collect(
Collectors.collectingAndThen(Collectors.toCollection(
() -> new TreeSet<>(Comparator.comparing(o -> o.getName()))), ArrayList<Aoo>::new));
System.out.println("list after operate : " + list);
}
}
class Aoo {
private String name;
public Aoo(String name) {
this.name = name;
}
public Aoo() {}