前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >java8 Streams API 详解(上) -- 入门篇

java8 Streams API 详解(上) -- 入门篇

作者头像
用户3147702
发布于 2022-06-27 06:55:41
发布于 2022-06-27 06:55:41
1K00
代码可运行
举报
运行总次数:0
代码可运行

1. 引言

多年前,我们在介绍 java8 新特性的时候,提到过作为 java8 一个亮点的新特性 -- streams api

但上文中只是简单介绍了 streams api 的基本用法,事实上,streams api 拥有十分强大的功能,能够大幅缩减编码量,有效提升编码效率与代码质量,达到事半功倍的效果。

本文我们就来详细介绍一下 streams api,来看看他究竟能做到多么强大

2. Streams API 面面观

2.1 Streams API 能做什么

Streams API 是对 java 中集合对象功能的增强,他可以让集合的操作变得更加便利、高效

他会自动通过并发执行的方式优化大批量数据集合的聚合操作,同时,结合另一个 java8 的新特性 -- Lambda 表达式,可以极大地提升编程效率,增加代码可读性

基于 jvm 底层的硬件优化,streams api 可以十分方便的利用多核性能,达到并发编程的效果,传统的并发编程往往因为其复杂性十分容易出错,但使用 streams api 则无需担心这个问题

2.2 Stream 是什么

stream 顾名思义,就是“流”,这个名字突出了集合对象流式处理的含义

说到“流式处理”,读者朋友们肯定并不陌生,在 java 中,迭代器就是一种通用的流式处理手段,stream 可以看成是迭代器的高级版本,他不保存数据,他只负责执行预定的算法和计算过程,因此 stream 很像是迭代器的函数式编程版本

和迭代器一样,stream 也是对集合单向遍历一次,并且不可以回头往复,但不同的是,stream 支持了这个过程的自动并发执行,并且将遍历过程变得更加简洁易读

2.3 Stream 的构成

一个流的使用通常包括三个基本步骤:

  1. 获取数据源
  2. 数据转换 -- Intermediate
  3. 执行操作 -- Terminal

其中,数据转换操作是以数据源为输入,进行一些操作后返回一个新的流进行接下来操作,数据转换操作可以多次进行,从而让整个流变成一个流管道:

最终,一个流只能有一个 terminal 执行操作,作为流的终结,他生成一个结果或一个 side effect

事实上,真正触发流的遍历操作的就是 terminal 操作的执行

除此以外,如果流的输入是一个无限大的集合,那么还必须具有 short-circuiting 操作,他有两个作用:

  1. 对于一个 intermediate 操作,如果它接受的是一个无限大(infinite/unbounded)的 Stream,但返回一个有限的新 Stream
  2. 对于一个 terminal 操作,如果它接受的是一个无限大的 Stream,但能在有限的时间计算出结果

2.4 流能做什么

知道了 Streams Api 的构成,你可能会很好奇,Streams 究竟可以做到哪些实用的事情呢?对我们的编程又有多大的帮助呢?

下面来看一个小例子,假设我们有一个学生集合,需要对这个集合中分数大于 80 的对象按照他们的 score 进行排序,并且返回由这些对象的 id 组成的 List<Long> 类型集合,我们应该怎么做呢?

2.4.1 java7 版本

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    private static List<Long> sortStudents(List<Student> students) {
        List<Student> studentsOverThreshold = new ArrayList<>();
        for (Student student: students) {
            if (student.getScore() >= THRESHOLD) {
                studentsOverThreshold.add(student);
            }
        }
        Collections.sort(studentsOverThreshold, new Comparator<Student>() {
            @Override
            public int compare(Student student1, Student student2) {
                return student2.getScore().compareTo(student1.getScore());
            }
        });
        List<Long> idResultList = new ArrayList<>();
        for (Student student : studentsOverThreshold) {
            idResultList.add(student.getId());
        }
        return idResultList;
    }

虽然整个流程中规中矩,但从可读性上来说并不是十分的一目了然

2.4.2 Streams API 版本

下面,我们使用 Streams API 来优化上面的代码,整个流程就会显得简单了很多:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    private static List<Long> sortStudents(List<Student> students) {
        return students.stream()
                .filter(t -> t.getScore() >= THRESHOLD)
                .sorted(Comparator.comparingLong(Student::getScore).reversed())
                .map(Student::getId)
                .collect(Collectors.toList());
    }

相较于上述代码,Streams API 版本的代码显然更加简洁和清晰,可读性、可维护性都有了显著提升,并且如果使用并发模式,Streams API 版本还会在性能上得到增强

由此可见,如果熟练掌握了 Streams API,那么在你的开发过程中,效率会大幅提升,Streams API 的灵活运用也会让你的程序拥有更好的可维护性

3. 流的创建

流的创建方式有很多种:

3.1 从 Collection 和数组创建流

  1. Collection.stream()
  2. Collection.parallelStream()
  3. Arrays.stream(T array)
  4. Stream.of(T array)
  • 额外一提,java8 除了通用的 Stream 外,还为基本数值类型提供了 IntStream、LongStream、DoubleStream 三种包装类型可供使用

3.2 通过 BufferedReader 读取

  • java.io.BufferedReader.lines()

3.3 通过静态工厂生成流

  1. java.util.stream.IntStream.range()
  2. java.nio.file.Files.walk()

3.4 其他创建方式

  1. 自定义构建 -- java.util.Spliterator
  2. 随机数流 -- Random.ints()
  3. 位操作流 -- BitSet.stream()
  4. 字符流 -- Pattern.splitAsStream(java.lang.CharSequence)
  5. jar 文件内容流 -- JarFile.stream()

4. 流的操作

上面我们已经提到,流共有三种操作:

  1. Intermediate 操作
  2. Short-Circuiting 操作
  3. Terminal 操作

下面,我们就来介绍一下这三大类操作中具体有哪些操作

4.1 Intermediate 操作

Intermediate 操作的输入是已经创建好的流,输出是进行转换后的流,主要有以下操作:

  • map -- 将输入流转换为另一个流
  • mapToInt/mapToLong -- 将转换结果的原始数值自动包装,转换后生成一个 IntStream/LongStream
  • flatMap -- 转换后生成多于原集合数量的新元素流
  • filter -- 过滤只保留符合条件的元素
  • distinct -- 去重
  • sorted -- 排序
  • peek -- 执行一个无返回的操作,不影响原来的流
  • limit -- 保留流的前 N 个元素,可以用于无限元素的流,作为 Short-circuiting 操作
  • skip -- 跳过流的前 N 个元素
  • parallel -- 让流并行化
  • sequential -- 让流串行化
  • unordered -- 删除流的有序标记,不强制让流有序

4.2 Terminal 操作

在一系列 Intermediate 操作之后,一定需要一个终极操作,来对流中的数据做最终的处理,这个“终极操作”就是 Terminal 操作,它包括:

  • forEach -- 对流中每个元素执行相同的操作
  • forEachOrdered -- 对流中每个元素有序地执行相同的操作
  • toArray -- 将流转换为数组返回
  • reduce -- 将流中所有数据汇总执行一个操作,返回一个值
  • collect -- 将流中所有参数汇总为一个集合并返回
  • min -- 求流中数据最小值
  • max -- 求流中数据最大值
  • count -- 计算流中的数据量
  • anyMatch -- 有任何元素命中规则则返回 true,可以用于无限元素的流,作为 Short-circuiting 操作
  • allMatch -- 全部元素均命中规则时返回 true,可以用于无限元素的流,作为 Short-circuiting 操作
  • noneMatch -- 全部元素均未命中规则时返回 true,可以用于无限元素的流,作为 Short-circuiting 操作
  • findFirst -- 返回首个命中规则的元素,可以用于无限元素的流,作为 Short-circuiting 操作
  • findAny -- 返回所有命中规则的元素,可以用于无限元素的流,作为 Short-circuiting 操作
  • iterator -- 返回由流数据构造的迭代器

4.3 Short-circuiting

当你要处理无限数据的集合时,通过 short circuiting 操作让程序能够在有限的时间内返回显然是非常必要的

包括上述已经标记过可以用作 Short-circuiting 操作的:

  • anyMatch
  • allMatch
  • noneMatch
  • findFirst
  • findAny
  • limit

5. 后记

本文我们通过一个例子看到了 Streams API 是如何使用的,以及列出了 java8 中 Streams API 包含的所有操作

那么,这些操作具体应该如何使用呢?敬请关注下一篇文章,详细介绍每一种操作

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-09-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小脑斧科技博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
java8 Streams API 详解(下)-- 详解 Stream 操作
上一篇文章中,我们介绍了 Streams API 是如何使用的,以及列出了 java8 中 Streams API 包含的所有操作。
用户3147702
2022/06/27
7750
java8 Streams API 详解(下)-- 详解 Stream 操作
Java8中的Stream API详解
在传统的J2EE应用中,Java代码经常不得不依赖于关系型数据库的聚合操作来完成诸如:
用户4396583
2024/08/03
1640
Java 8 中的 Streams API 详解
Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream。Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。
编程十年
2019/09/17
1.2K0
Java8 Stream api 入门
Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream。
呼延十
2019/07/01
7330
Java8---Stream的介绍和相关概念(1)
        Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream。Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。
IT云清
2019/01/22
5440
Java 基础概念·Java Stream
Stream 和其它集合类的区别在于:其它集合类主要关注与有限数量的数据的访问和有效管理(增删改),而 Stream 并没有提供访问和管理元素的方式,而是通过声明数据源的方式,利用可计算的操作在数据源上执行。
数媒派
2022/12/01
1.1K0
JDK8系列之Stream API入门教程和示例
在前面的章节的学习中,我们学习了jdk8的新特性,lambada表达式、方法引用、函数式接口等等,接着本博客继续JDK8的一个比较重要的特性,JDK8 Stream API
SmileNicky
2021/07/21
7290
Java 8 Stream 从入门到进阶——像SQL一样玩转集合
所以有没有这样一种方式可以让我们不再使用一遍又一遍的循环去处理集合,而是能够便捷地操作集合?
翊君
2022/03/08
6680
Java 8 Stream 从入门到进阶——像SQL一样玩转集合
Java8函数式编程
最近使用lambda表达式,感觉使用起来非常舒服,箭头函数极大增强了代码的表达能力。于是决心花点时间深入地去研究一下java8的函数式。
全栈程序员站长
2022/07/21
6570
Java8函数式编程
Java8 Stream的总结
Stream是Java 8新增的接口,Stream可以认为是一个高级版本的 Iterator。它代表着数据流,流中的数据元素的数量可以是有限的,也可以是无限的。
fengzhizi715
2018/08/24
3920
Java8 Stream的总结
2021最新 JDK17 之 JAVA基础 Stream 流
Java 8之前的集合类库主要依赖于 外部迭代(external iteration)。 Collection实现 Iterable接口,从而使得用户可以依次遍历集合的元素。比如我们需要把一个集合中的形状都设置成红色,那么可以这么写:
猫头虎
2024/04/07
2210
2021最新 JDK17 之 JAVA基础 Stream 流
Java8特性接口的改变LambaStream时间API
函数式接口,该接口中只能由一个抽象方法,可以使用@FunctionalInterface注解修饰某个接口有且仅有一个抽象方法。
spilledyear
2018/10/09
4350
一次性实战java8 新特性(全)—— Lambda、Optional、stream、DateTime
本篇博客你将学到: 1.Lambda表达式 2.Optional类,告别空指针异常 3.Stream流式处理 4.时间处理LocalDate、LocalTime、LocalDateTime、ZonedDateTime、Clock、Duration 5.重复注解 6.扩展注释 7.更好的类型推荐机制 8.参数名字保存在字节码中 9.异步调用 CompletableFuture
源码之路
2020/09/03
2.6K0
【小家java】java8新特性之---Stream API 详解 (Map-reduce、Collectors收集器、并行流、groupby多字段分组)
Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。
YourBatman
2019/09/03
3.3K0
【小家java】java8新特性之---Stream API 详解  (Map-reduce、Collectors收集器、并行流、groupby多字段分组)
Java8新特性之Stream流(基础篇)
对于流的处理,主要有三种关键性操作:分别是流的创建、中间操作(intermediate operation)以及最终操作(terminal operation)。
Remember_Ray
2020/08/03
1.9K1
Java8学习之Stream(流)
本文讲述.stream()的内容,需要一些Lambda表达式的基础,之前也推送过关于Lambda表达式和Stream的相关内容,就看哪盘菜味道更好!
用户5927304
2019/07/31
1.1K0
还看不懂同事的代码?超强的 Stream 流操作姿势还不学习一下
我们都知道 Lambda 和 Stream 是 Java 8 的两大亮点功能,在前面的文章里已经介绍过 Lambda 相关知识,这次介绍下 Java 8 的 Stream 流操作。它完全不同于 java.io 包的 Input/Output Stream ,也不是大数据实时处理的 Stream 流。这个 Stream 流操作是 Java 8 对集合操作功能的增强,专注于对集合的各种高效、便利、优雅的聚合操作。借助于 Lambda 表达式,显著的提高编程效率和可读性。且 Stream 提供了并行计算模式,可以简洁的编写出并行代码,能充分发挥如今计算机的多核处理优势。
未读代码
2019/11/25
5560
Java8 Stream流
关注公众号(CoderBuff)回复“stream”获取《Java8 Stream编码实战》PDF完整版。
用户1148394
2020/03/25
1.4K0
【Java8新特性】03 Stream流式数据处理
【Java8新特性】02 函数式接口和Lambda表达式实战练习:环绕执行模式使行为参数化
爱笑的架构师
2020/09/24
1.4K0
【Java8新特性】03 Stream流式数据处理
Stream使用这么久,它是如何提高遍历集合效率?
对于List 集合类,我想大家肯定很了解了,那我想一定也知道集合的顶端接口 Collection。在 Java8 中,Collection 新增了两个流方法,分别是 Stream() 和 parallelStream()
码农架构
2020/10/26
9090
Stream使用这么久,它是如何提高遍历集合效率?
推荐阅读
相关推荐
java8 Streams API 详解(下)-- 详解 Stream 操作
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验