描述一下有关流的概念
1、关于流
Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。
Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。
而和迭代器又不同的是,Stream 可以并行化操作,迭代器只能命令式地、串行化操作。顾名思义,当使用串行方式去遍历时,每个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程。Java 的并行 API 演变历程基本如下:
- 1.0-1.4 中的 java.lang.Thread
- 5.0 中的 java.util.concurrent
- 6.0 中的 Phasers 等
- 7.0 中的 Fork/Join 框架
- 8.0 中的 Lambda
2、流的构成
当我们使用一个流的时候,通常包括三个基本步骤:
获取一个数据源(source)→ 数据转换→执行操作获取想要的结果,每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道,如下图所示。
图 1. 流管道 (Stream Pipeline) 的构成
有多种方式生成 Stream Source:
从 Collection 和数组Collection.stream()
Collection.parallelStream()
Arrays.stream(T array) or Stream.of()
从 BufferedReader
java.io.BufferedReader.lines()
静态工厂
java.util.stream.IntStream.range()
java.nio.file.Files.walk()
自己构建
java.util.Spliterator
其它
Random.ints()
BitSet.stream()
Pattern.splitAsStream(java.lang.CharSequence)
JarFile.stream()
3、流的操作类型分为两种:
- Intermediate:一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
- Terminal:一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
在对于一个 Stream 进行多次转换操作 (Intermediate 操作),每次都对 Stream 的每个元素进行转换,而且是执行多次,这样时间复杂度就是 N(转换次数)个 for 循环里把所有操作都做掉的总和吗?其实不是这样的,转换操作都是 lazy 的,多个转换操作只会在 Terminal 操作的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream 里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在 Terminal 操作的时候循环 Stream 对应的集合,然后对每个元素执行所有的函数。
还有一种操作被称为 short-circuiting。用以指:
对于一个 intermediate 操作,如果它接受的是一个无限大(infinite/unbounded)的 Stream,但返回一个有限的新 Stream。对于一个 terminal 操作,如果它接受的是一个无限大的 Stream,但能在有限的时间计算出结果。
当操作一个无限大的 Stream,而又希望在有限时间内完成操作,则在管道内拥有一个 short-circuiting 操作是必要非充分条件。
4、流与集合
说白了,集合是针对数据的,体现是是一种数据存储结构;而流是针对计算的,体现的是更多一种对数据的计算方式,就比如整个流水线,当执行到这一步的时候才会去做相应的计算,也就是按需来计算。
5、流的迭代和常用的操作
public void test(){ List<String> views = Lists.newArrayList("wsbs","xwzx","bmfw","wshd"); // 外部迭代,也就是一种显式的迭代方式, // 因为它不属于stream的一种操作,不具有stream的并行特点,需要自己去考虑到并行问题 views.iterator().forEachRemaining(System.out::println); System.out.println("--------------------"); // 内部迭代,使用stream在内部实现的一种迭代方式,其本身会并行化处理 Stream<String> s = views.stream(); s.forEach(System.out::println); // 此地方会报错,因为stream只能被迭代一次: // 异常:stream has already been aperated upon or close s.forEachOrdered(System.out::println); }
stream除了中间计算阶段,相应的也会有结束阶段,不可能会一直计算下去的,要是一直计算,访问量大的时候那不得分分钟死掉。
操作 | 类型 | 返回类型 | 操作参数 | 函数描述符 |
filter | 中间操作 | Stream<T> | Predicate<T> | T -> boolean |
map | 中间操作 | Stream<T> | Function<T, R> | T -> R |
limit | 中间操作 | Stream<T> | ||
sorted | 中间操作 | Stream<T> | Comparator<T> | (T, T) -> int |
distinct | 中间操作 | Stream<T> |
forEach | 终端操作 | 遍历流中的每个元素并对其应用lambda |
count | 终端操作 | 返回流中的元素个数,返回long型 |
collect | 终端操作 | 把流规约成一个集合,比如:Collectors.toList()、Map、Set ... (后面会详细介绍) |
相关推荐
Java 记录随笔 Java 记录随笔是关于 Java 软件架构设计的笔记,涵盖了软件架构的基本原则、当前流行的技术、数据库存储结构、Web 界面用户接口层、业务层架构、持久层技术、XML 结构化信息传输和存储的重要性等多个...
JAVA_HOME="/usr/lib/jvm/java-8-oracle" PATH="$PATH:$JAVA_HOME/bin" ``` 保存并关闭文件,然后使更改生效: ```bash source /etc/environment ``` 接下来,我们需要安装MySQL 5.7。同样地,使用apt来安装: `...
每四位二进制数对应一个十进制数,如二进制的1101代表十进制的13,因为1*8 + 1*4 + 0*2 + 1*1 = 8 + 4 + 0 + 1 = 13。8421码在某些特定的数字处理场景中很有用,如电子表格软件或计算器。 Java中的位运算,如与(&)...
在Java世界,Map对象转换为实体类通常是通过ORM框架如MyBatis Plus完成的,而实体类转化为JSON则可以借助Jackson或Gson库。例如,使用Gson库,可以写成`Gson gson = new Gson(); String jsonString = gson.toJson...
9. **帮助文档**:附带的开发随笔手册可能包含关于如何使用该记事本的详细说明,对于初学者来说非常有帮助。 开发这样的程序需要对Java语言、SWT库以及面向对象设计有深入理解。通过这个项目,开发者不仅可以掌握...
标题“2014210-2014307笔记随笔”暗示了这是一份时间跨度从2014年2月10日至3月7日的个人学习记录,可能包含了作者在IT领域的所学所悟,特别是关于编程、软件开发或系统设计的思考。由于描述部分为空,我们无法直接...
在开发“Android App_云随笔课程设计”项目时,我们面临的是构建一个移动应用程序,旨在帮助用户便捷地记录他们的日常生活、旅行体验、心情点滴以及学习笔记等。这个应用程序的关键特性在于其同步功能,它将用户的...
JavaThings-Java安全漫谈笔记相关《 Java安全漫谈》是我在写的一点Java学习相关的随笔,不是很严谨,也不是啥高科技。这个存储库主要是记录并整理一下,附加一些代码。Java安全漫谈目录 人口统计字节码:远程字节码...
Ibatis 是一款轻量级的Java持久层框架,它的核心思想是将SQL语句与Java代码分离,使得开发者可以更加灵活地控制SQL的编写,同时避免了传统的JDBC中的大量模板代码,提高了开发效率和代码的可维护性。在本文中,我们...
例如,可能会讲解使用如Python、C++或Java等语言进行系统开发,或者如何利用现有的开源项目如OPC-UA、Modbus等进行通信协议的实现。源码分析部分可能涉及代码调试、性能优化和错误处理等内容。 “工具”标签表明...
Apache Log4j2 是一个广泛使用的Java日志记录库,它提供了一个强大和灵活的方式来记录应用程序事件。Log4j2手册详细介绍了该库的各个方面,包括架构、迁移、API、配置、Web应用程序集成、插件、查找、Appenders、...
基于JAVA幼儿园家园共育平台设计与实现 开发语言 JavaWeb前端语言 开发工具:六年特雷利JIDEA ...童言稚语:每月记录一次幼儿有趣的话语,文字展示。 育儿头条:育儿新闻文章。管理员上传,可评论点赞
java 源码 博客 一杯82年的JAVA 大家好,我是练习时常两年半的JAVA练习生,爱好是 ...博客专用仓库,主要记录一些学习和实践的总结,感兴趣的朋友可以点个watch或star。 随笔 探索JAVA并发 从0.5到1写个RPC框架
无论是通过阅读"课堂问题随笔.txt"来解决疑惑,还是通过"必须记住的代码君们"来熟悉常用代码,亦或是通过"Entertainment"中的项目来提升编程技巧,都能有效地促进Java学习的进程。同时,"总结文件"和"瞎搞"部分则...
1. **技术基础知识**:随笔可能涵盖基础的编程语言知识,如Python、Java或C++的语法特性,数据结构和算法的应用,以及软件工程的基本原则。 2. **项目经验分享**:作者可能会分享他们在实际项目中遇到的问题及解决...
列表参考国光大佬的国光的安全随笔记录 安全技能 该技能表不用按顺序进行学习,但是比较高级的我会放最后面,因为我也不会,需要花时间慢慢加。 总结我这几年的一点经验:安全需要学习的技术太多了,特别是红队、...
Java自动内存管理机制包含两部分:内存分配和内存回收,要想理解内存分配和回收的机制,则需要了解下Java内存区域(Java运行时数据区),这篇随笔将按照下面的线索进行逐步解析:1.Java运行时数据区2.对象“已死”的...
3. 在代码中使用:在Java代码中,通过Logger类获取日志实例,然后调用如info(), warn(), error()等方法记录日志。 四、日志子文件Logger 压缩包中的"Logger"可能是具体的日志实现类或配置文件。如果是类文件,它...
MiaoWu毕业设计-流浪猫收养系统过程随笔记录通知:1.用户关注用户2.关注的用户发帖3.帖子审核结果4.领养申请5.领养审核结果发帖:需发帖人有联系方式帖子详情页 数据获取顺序调整实现头像修改功能修改记录1.修改猫咪...