最近在阅读 Java 核心技术卷2高级特性时,由于是英文文档,就试着翻译了一下,其中部分单词还是需要借助 Google 翻译,希望在之后的阅读翻译过程中,会有很大的进步。
1.1 从迭代到流操作
当处理一个集合时,你通常通过迭代遍历集合的每一个元素并对其进行操作。例如,我们想统计一本书中的长单词,首先,我们要把它们放进 list 中
1 | String contents = new String(Files.readAllBytes( |
然后我们开始迭代
1 | int count = 0; |
当用到 stream 时,同样的操作可能是这样的。
1 | long count = words.stream() |
现在,无需通过循环来获得过滤和计数的节点,方法名称即可告知你代码打算做什么。此外,在循环详细规定了操作顺序的情况下,只要结果正确,stream 就可以按其希望的任何方式调度操作。
只要把 stream 改为 parallelStream,就可以使 stream library 并行过滤以及计数
1 | long count = words.parallelStream() |
Streams 遵循“是什么,而不是怎么做”的原则,在最初的流示例中,我们描述了需要做到什么:获得长单词并对其计数。我们没有指明过滤的顺序以及线程。相反,本节开头的循环遍历指定了过滤的工作方式,从而放弃了任何优化此过滤的机会。
流从表面上看的话,与集合类似,允许你转换并操作数据,但是它们两者之间有根本性的区别。
- 流不存储它的元素,它们可以存储在基础的集合中或者通过指令来生成
- 流的操作不会改变其原来的数据源。例如,filter() 方法不会从新的流中移除元素,但是会生成一个不存在它们的新流。
- 流的操作是懒加载的,就是说如果结果不需要的话,它们是不会继续执行的。例如,如果你只需要前五个长单词而不是全部,filter 方法将在匹配到第五个长单词后停止过滤。结果,你甚至可以有无限的流。
让我们来看一个其他的例子,stream() 与 parallelStream() 方法生成了包含单词列表的流,filter() 方法返回了一个新的包含那些长度大于12的长单词的流,count() 方法将该流减少为结果。
当你使用流时,可以通过以下三步操作来进行。
- 创建一个 stream
- 指定将初始的流转化为其他流的步骤
- 应用终端操作来产生结果,此操作将强制执行之前的惰性操作。之后,将无法使用该流。
在 1.1 中的例子,用 stream() 或者 parallelStream() 方法来创建流,filter() 方法会处理这个流,count() 方法会产生最终结果。
以下是 1.1 中所用的部分代码
1 | 1 package streams; |