Java8 新特性之 Stream 学习

379 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情

1. Stream 介绍

1.1 什么是 Stream

Stream 将要处理的元素集合看作一种流,在流的过程中,借助 Stream 类提供的 API 方法可以对流中的元素进行操作,如筛选、排序、聚合等。

Stream 操作拥有以下特性:

  1. Stream 不存储数据,而只是按照特定的规则对数据进行计算,并最终输出结果

  2. Stream 不会改变源数据内容,操作之后的流会生成一个新的集合或值

  3. Stream 具有延迟执行的特性,只有当调用终端操作时,中间操作才会执行

1.2 如何创建 Stream

Stream 的创建不止一种方式,可以根据数据的格式选择合适的创建方式

  • 集合创建,Collection 的 stream() 方法,IntStream stream = list/set.stream();

  • 数组创建,Arrays 的 stream() 方法,IntStream stream = Arrays.stream(array);

  • Stream 的静态方法,如 of、iterate、generate 等,可以传入数据源并返回 Stream 结果

// 参数可以传入多个参数,生成 Stream 流对象
Stream.of(1,2,3,4,5);

// 传入初始元素和步幅,根据规则产生有序的队列
Stream.iterate(0, (x) -> x+3).limit(4);

// 根据参数指定的方法产生无序的序列
Stream.gengrate(Math::random).limit(4);
  • 文件流,Files 的 lines() 方法,文件生成的每个流是文件中的一行数据
Stream<String> lines = Files.lines(Paths.get("test.txt"), Charset.defaultCharset())

1.3 Stream 流的种类

Stream 根据流的种类和内容机制可以分为顺序流和并行流

  • 顺序流,即 Stream,上述方法生成的皆是顺序流

  • 并行流,即 ParallelStream,可以通过 list.parallelStream() 方式创建并行流

  • 顺序流可以通过方法转换成为并行流,list.stream().parallel();

1.4 Stream 调试

在程序中,如果使用了 Stream 流式表达式,则在调试流程中默认是无法进入流过程中,可以在 IDEA 中设置开启。

  • IDEA 控制台按钮最右侧:Trace Current Stream Chain

2. Stream 使用(过程操作)

在 Stream 流中,元素是以 Optional 类型存在的,Optional 也是 Java8 新增加的类型,它通过对对象的封装来减少判断对象为 null 的情况,使用时可以更加关注程序本身。

2.1 filter 筛选

通过使用 filter 方法进行条件筛选,filter 的方法参数为一个条件,使用时对流通过指定条件进行过滤,最终返回满足条件的流。

list.stream().filter(o -> o.getId() == userId);

2.2 distinct 去重复

distinct 方法可以对集合中的元素进行去重处理,主要针对集合中元素为基本类型或字符串时使用。

list.stream().distinct();

2.3 sort 排序

sort 方法可以对流中的元素按照自然顺序或自定义顺序排序,也可以对排序序列反转。

list.stream().sorted();

2.4 map 映射

map 方法可以接收一个 Function 函数,该函数会应用到流中的每个元素,并最终得到映射的元素结果。

// 流中元素转小写
Arrays.stream(array).map(String::toUpperCase);

2.5 foreach 遍历

foreach 方法类似 Java 中的 for 循环,可以将 Stream 流中的元素进行循环遍历,并进行相关的处理。

// 生成流并遍历打印流中的元素
Stream.of(1, 2, 3, 4, 5, 6).forEach(System.out::println);

3. Stream 使用(结果操作)

使用中间操作处理 Stream 流得到的结果仍然是流,要想得到 Java 中对应的数据类型,还需要使用 Stream 的结果操作,并指定流转成的对象类型。

3.1 collect() 收集

collect() 收集方法可以将流中的元素按照指定方式收集起来,并转成指定类型数据。

最常见的即将处理后的 List 流转成 List 结构

List list = list.stream().filter(o -> o.getId() == userId).collect(Collectors.toList());

除了 Collectors.toList() 方法,Collectors 中还提供了 .toSet() 和 .toMap() 等类型的转换方法。

3.2 count 统计

除了直接转成集合类型,还可以使用统计的方式来对流进行结果操作,如对流中的元素计算数量、累加值、平均值等操作。

// 计算数量
Long count = personList.stream().collect(Collectors.counting());

Collectors 中还有其他如 averagingInt() 和 maxBy() 等方法。

3.3 groupingBy 分组

根据流中的对象中指定属性,实现对流中对象分组后执行结果操作,返回分组类型 Map<Type,Object>

Map<Type,User> map = list.stream().collect(groupingBy(User::getName));

4 总结

本篇文章先对 Stream 的整体有个初步认识,具体的方法使用接下来继续输出!