作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
学习必须往深处挖,挖的越深,基础越扎实!
阶段1、深入多线程
阶段2、深入多线程设计模式
阶段3、深入juc源码解析
码哥源码部分
码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】
码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】
码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】
码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】
打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】
什么是 Stream API
Stream API
是 Java 8 引入的一个用于对集合数据进行函数式编程操作的强大的库。它允许我们以一种更简洁、易读、高效的方式来处理集合数据,可以极大提高 Java 程序员的生产力,是目前为止对 Java 类库最好的补充。
Stream API
的核心思想是将数据处理操作以函数式的方式链式连接,以便于执行各种操作,如过滤、映射、排序、归约等,而无需显式编写传统的循环代码。
下面是 Stream API
的一些重要概念和操作:
Stream
****(流):Stream
是 Java 8 中处理集合的关键抽象概念,它是数据渠道,用于操作数据源所生成的元素序列。这些数据源可以来自集合(Collection
)、数组、I/O
操作等等。它具有如下几个特点:Stream
不会存储数据。Stream
不会改变源数据对象,它返回一个持有结果的新的Stream
。Stream
操作是延迟执行的,这就意味着他们要等到需要结果的时候才会去执行。
- 中间操作:这些操作允许您在
Stream
上执行一系列的数据处理。常见的中间操作有filter
(过滤)、map
(映射)、distinct
(去重)、sorted
(排序)、limit
(截断)、skip
(跳过)等。这些操作返回的仍然是一个 Stream。 - 终端操作:终端操作是对流进行最终处理的操作。当调用终端操作时,流将被消费,不能再进行进一步的中间操作。常见的终端操作包括
forEach
(遍历元素)、collect
(将元素收集到集合中)、reduce
(归约操作,如求和、求最大值)、count
(计数)等。 - 惰性求值:Stream 操作是惰性的,只有在调用终端操作时才会执行中间操作。这可以提高性能,因为只处理需要的数据。
为什么要用 Stream API
作为一个 CRUD Boy ,在实际开发中,我们的数据来源大多数都是基于数据库、文件等等,一般情况下这些数据都需要我们用 Java 程序来处理。这时有小伙伴就说,我用 for 循环就能很好的处理集合数据了,为什么偏要用 Stream API
呢?其实相比传统集合处理方式,Stream API 有很多优点:
- 简洁和可读性:Stream API 的链式操作使代码更加简洁、可读。
- 不可变性:Stream 操作不会修改原始数据,而是创建一个新的 Stream,确保了原始数据的不可变性,有助于并发编程。
- 惰性求值:Stream 操作是惰性的,只有在调用终端操作时才会触发中间操作的执行,提高了性能,因为只处理需要的数据。
- 并行处理:Stream API 支持并行处理数据,可以充分利用多核处理器,提高性能。
- 更高的效率:使用 Stream API 可以更快速地编写代码,因为它减少了样板代码的编写,同时提供了丰富的操作。
Stream 与集合的差异是:Stream 讲的是计算,而集合讲的是数据。
Stream 操作三部曲
一个完整的 Stream 操作包括三步
创建 Stream
首先我们需要一个 Stream 对象,常见的创建方式有:
- 使用集合的
stream()
方法
在集合中有两个方法可以创建 Stream 对象:
default Stream<E> stream():返回一个顺序流
default Stream<E> parallelStream():返回一个并行流
- 通过数组
Arrays.stream(T[] array)
,将数组转换为 Stream 对象:
String[] array = {"死磕 Java","死磕 Java 并发","死磕 Java 新特性","死磕 Netty"};
Stream<String> stream = Arrays.stream(array);
- 使用
Stream.of(T... values)
方法
Stream<String> stream = Stream.of("死磕 Java","死磕 Java 并发","死磕 Java 新特性","死磕 Netty");
这种方式适用于直接提供一组元素来创建Stream。
- 使用
Stream.builder()
方法
Stream 提供了一个 builder()
方法来提供构建 Stream 的构造器:
Stream.Builder<String> builder = Stream.builder();
builder.accept("死磕 Java");
builder.accept("死磕 Java 并发");
builder.accept("死磕 Java 新特性");
builder.accept("死磕 Netty");
Stream<String> stream = builder.build();
这种方式适用于需要逐个添加元素到Stream中的情况。
Stream.generate()
orStream.iterate(T seed, UnaryOperator<T> f)
这两个方法都是用于生成无限元素的Stream,需要通过limit()
方法来限制元素数量。
Stream<String> stream = Stream.generate(() -> "a").limit(3);
这两个方法使用比较少。
中间操作
有了 Stream 对象,就可以在 Stream 上应用中间操作。
中间操作是一系列的操作,对数据源的数据进行处理,例如过滤、映射、排序、去重等等。注意这些操作不会立即执行,而是构建一个操作链。下表是 Stream 中常用中间操作方法。
方法名 | 描述 |
---|---|
filter(Predicate<T> predicate) |
根据给定的谓词条件过滤元素。 |
map(Function<T, R> mapper) |
将元素通过给定的函数映射为另一个类型的元素。 |
flatMap(Function<T, Stream<R>> mapper) |
将每个元素映射为一个流,然后将这些流合并为一个流。 |
distinct() |
去除流中的重复元素。 |
sorted() |
对元素进行排序,默认按自然顺序排序。 |
sorted(Comparator<T> comparator) |
使用 |