@@ -1683,15 +1683,15 @@ Signal(dash)
16831683## 终端操作
16841684
16851685
1686- 这些操作接收一个流并产生一个最终结果;它们不会向后端流提供任何东西。因此,终端操作总是你在管道中做的最后一件事情 。
1686+ 以下操作将会获取流的最终结果。至此我们无法再继续往后传递流。可以说,终端操作总是我们在流管道中所做的最后一件事 。
16871687
16881688< ! -- Convert to an Array -- >
16891689
1690- ### 转化为数组
1690+ ### 数组
16911691- `toArray()`:将流转换成适当类型的数组。
1692- - `toArray(generator)`:在特殊情况下,生成器用于分配自定义的数组存储 。
1692+ - `toArray(generator)`:在特殊情况下,生成自定义类型的数组 。
16931693
1694- 这组方法在流操作产生的结果必须是数组形式时很有用。假如我们想在流里复用获取的随机数,可以将他们保存到数组中 。代码示例:
1694+ 当我们需要得到数组类型的数据以便于后续操作时,上面的方法就很有用。假设我们需要复用流产生的随机数时,就可以这么使用 。代码示例:
16951695
16961696```java
16971697// streams/RandInts.java
@@ -1706,19 +1706,19 @@ public class RandInts {
17061706}
17071707```
17081708
1709- 上例将100 个数值范围在 0 到 1000 之间的随机数流转换成为数组并将其存储在 `rints` 中,在每次调用 `rands()` 的时候可以重复获取相同的流 。
1709+ 上例将100 个数值范围在 0 到 1000 之间的随机数流转换成为数组并将其存储在 `rints` 中。这样一来,每次调用 `rands()` 的时候可以重复获取相同的整数流 。
17101710
17111711< ! -- Apply a Final Operation to Every Element -- >
1712- ### 应用最终操作
1712+ ### 循环
17131713
1714- - `forEach(Consumer )`:你已经看到过很多次 `System . out:: println` 作为 ** Consumer ** 函数。
1714+ - `forEach(Consumer )`常见如 `System . out:: println` 作为 ** Consumer ** 函数。
17151715- `forEachOrdered(Consumer )`: 保证 `forEach` 按照原始流顺序操作。
17161716
1717- 第一种形式:显式设计为任意顺序操作元素,仅在引入 `parallel()` 操作时才有意义 。在 [并发编程](24 - Concurrent - Programming . md) 章节之前我们不会深入研究这个问题。这里简单介绍下 `parallel()`:可实现多处理器并行操作。实现原理为将流分割为多个(通常数目为 CPU 核心数)并在不同处理器上分别执行操作。因为我们采用的是内部迭代,而不是外部迭代,所以这是可能实现的。
1717+ 第一种形式:无序操作,仅在引入并行流时才有意义 。在 [并发编程](24 - Concurrent - Programming . md) 章节之前我们不会深入研究这个问题。这里简单介绍下 `parallel()`:可实现多处理器并行操作。实现原理为将流分割为多个(通常数目为 CPU 核心数)并在不同处理器上分别执行操作。因为我们采用的是内部迭代,而不是外部迭代,所以这是可能实现的。
17181718
17191719`parallel()` 看似简单,实则棘手。更多内容将在稍后的 [并发编程](24 - Concurrent - Programming . md) 章节中学习。
17201720
1721- 下例引入了 `parallel()` 来帮助理解 `forEachOrdered(Consumer )` 的作用和使用场景。代码示例:
1721+ 下例引入 `parallel()` 来帮助理解 `forEachOrdered(Consumer )` 的作用和使用场景。代码示例:
17221722
17231723```java
17241724// streams/ForEach.java
@@ -1756,7 +1756,7 @@ public class ForEach {
17561756
17571757< ! -- Collecting -- >
17581758
1759- ### 收集
1759+ ### 集合
17601760
17611761- `collect(Collector )`:使用 ** Collector ** 收集流元素到结果集合中。
17621762- `collect(Supplier , BiConsumer , BiConsumer )`:同上,第一个参数 ** Supplier ** 创建了一个新结果集合,第二个参数 ** BiConsumer ** 将下一个元素包含到结果中,第三个参数 ** BiConsumer ** 用于将两个值组合起来。
@@ -1798,7 +1798,7 @@ stream, streams, throws, toCollection, trim, util,
17981798void, words2]
17991799```
18001800
1801- ** Files . ** `lines()` 打开 ** Path ** 并将其转换成为行流。下一行代码将匹配一个或多个非单词字符(`\\w+ `)行进行分割,然后使用 ** Arrays . ** `stream()` 将其转化成为流,并将结果扁平映射成为单词流 。使用 `matches(\\d+ )` 查找并移除全数字字符串(** 注意** ,`words2` 是通过的)。接下来我们使用 ** String . ** `trim()` 去除单词两边的空白,`filter()` 过滤所有长度小于3 的单词,紧接着只获取100 个单词,最后将其保存到 ** TreeSet ** 中。
1801+ ** Files . ** `lines()` 打开 ** Path ** 并将其转换成为行流。下一行代码将匹配一个或多个非单词字符(`\\w+ `)行进行分割,然后使用 ** Arrays . ** `stream()` 将其转化成为流,并将结果展平映射成为单词流 。使用 `matches(\\d+ )` 查找并移除全数字字符串(** 注意** ,`words2` 是通过的)。接下来我们使用 ** String . ** `trim()` 去除单词两边的空白,`filter()` 过滤所有长度小于3 的单词,紧接着只获取100 个单词,最后将其保存到 ** TreeSet ** 中。
18021802
18031803< ! --
18041804Files . lines() opens the Path and turns it into a Stream oflines. The next line splits those lines on boundaries of one or morenon- word characters (\\W + ), which produces an array which is turnedinto a Stream with Arrays . stream(), and the result is flat- mapped back into a Stream of words. The matches(\\d+ ) finds
@@ -1858,7 +1858,7 @@ public class MapCollector {
18581858
18591859在这里,我们只使用最简单形式的 `Collectors . toMap()`,这个方法值需要一个可以从流中获取键值对的函数。还有其他重载形式,其中一种形式是在遇到键值冲突时,需要一个函数来处理这种情况。
18601860
1861- 在大多数情况下,你可以在 `java.util.stream. Collectors `寻找到你想要的预先定义好的 ** Collector ** 。在少数情况下当你找不到想要的时候,你可以使用第二种形式的 ` collect()`。 我基本上把它留作更高级的练习,但是这里有一个例子给出了基本想法 :
1861+ 大多数情况下, `java.util.stream. Collectors ` 中预设的 ** Collector ** 就能满足我们的要求。除此之外,你还可以使用第二种形式的 ` collect()`。 我把它留作更高级的练习,下例给出基本用法 :
18621862
18631863< ! --
18641864The capChars randomly- generated Iterator of capitalletters starts as a stream, then the iterator() method allows us touse it in the stream() method
@@ -1893,13 +1893,13 @@ cheese
18931893
18941894< ! -- Combining All Stream Elements -- >
18951895
1896- ### 组合所有流元素
1896+ ### 组合
18971897
18981898- `reduce(BinaryOperator )`:使用 ** BinaryOperator ** 来组合所有流中的元素。因为流可能为空,其返回值为 ** Optional ** 。
18991899- `reduce(identity, BinaryOperator )`:功能同上,但是使用 ** identity** 作为其组合的初始值。因此如果流为空,** identity** 就是结果。
1900- - `reduce(identity, BiFunction , BinaryOperator )`:这个形式更为复杂(所以我们不会介绍它),在这里被提到是因为它使用起来会更有效 。通常,你可以显式地组合 `map()` 和 `reduce()` 来更简单的表达它。
1900+ - `reduce(identity, BiFunction , BinaryOperator )`:更复杂的使用形式(暂不介绍),这里把它包含在内,因为它可以提高效率 。通常,我们可以显式地组合 `map()` 和 `reduce()` 来更简单的表达它。
19011901
1902- 如下是一个用于演示 `reduce()` 的示例 :
1902+ 下面来看下 `reduce` 的代码示例 :
19031903
19041904```java
19051905// streams/Reduce.java
@@ -1946,20 +1946,20 @@ Frobnitz(7)
19461946Frobnitz(29 )
19471947```
19481948
1949- ** Frobnitz ** 包含了一个名为 `supply()` 的生成器;因为这个方法对于 `Supplier<Frobnitz > ` 是签名兼容的,我们可以将其方法引用传递给 `Stream . generate()`(这种签名兼容性被称作结构一致性)。我们使用没有给“起始值 ”的 `reduce()`方法,这意味着它的返回值是 ** Optional ** 类型的 。`Optional . ifPresent()` 只有在结果非空的时候才会调用 `Consumer<Frobnitz > ` (`println` 方法可以被调用是因为 ** Frobnitz ** 可以通过 `toString()` 方法转换成 ** String ** )。
1949+ ** Frobnitz ** 包含了一个名为 `supply()` 的生成器;因为这个方法对于 `Supplier<Frobnitz > ` 是签名兼容的,我们可以将其方法引用传递给 `Stream . generate()`(这种签名兼容性被称作结构一致性)。无“初始值 ”的 `reduce()`方法返回值是 ** Optional ** 类型 。`Optional . ifPresent()` 只有在结果非空的时候才会调用 `Consumer<Frobnitz > ` (`println` 方法可以被调用是因为 ** Frobnitz ** 可以通过 `toString()` 方法转换成 ** String ** )。
19501950
19511951Lambda 表达式中的第一个参数 `fr0` 是上一次调用 `reduce()` 的结果。而第二个参数 `fr1` 是从流传递过来的值。
19521952
1953- `reduce()` 中的 Lambda 表达式使用了三元表达式来获取结果,当其 size 小于 50 的时候获取 `fr0` 否则获取序列中的下一个值 `fr1`。因此你会取得第一个 size 小于 50 的 `Frobnitz `,只要找到了就这个结果就会紧紧地攥住它,即使有其他候选者出现。虽然这是一个非常奇怪的约束,但是它确实让你对 `reduce()` 有了更多的了解。
1953+ `reduce()` 中的 Lambda 表达式使用了三元表达式来获取结果,当其长度小于 50 的时候获取 `fr0` 否则获取序列中的下一个值 `fr1`。当取得第一个长度小于 50 的 `Frobnitz `,只要得到结果就会忽略其他。这是个非常奇怪的约束, 也确实让我们对 `reduce()` 有了更多的了解。
19541954
19551955< ! -- Matching -- >
19561956### 匹配
19571957
1958- - `allMatch(Predicate )` :如果流的每个元素根据提供的 ** Predicate ** 都返回 true 时,结果返回为 true 。这个操作将会在第一个 false 之后短路;也就是不会在发生 false 之后继续执行计算 。
1959- - `anyMatch(Predicate )`:如果流中的任意一个元素根据提供的 ** Predicate ** 返回 true 时,结果返回为 true 。这个操作将会在第一个 true 之后短路;也就是不会在发生 true 之后继续执行计算 。
1960- - `noneMatch(Predicate )`:如果流的每个元素根据提供的 ** Predicate ** 都返回 false 时,结果返回为 true 。这个操作将会在第一个 true 之后短路;也就是不会在发生 true 之后继续执行计算 。
1958+ - `allMatch(Predicate )` :如果流的每个元素根据提供的 ** Predicate ** 都返回 true 时,结果返回为 true 。在第一个 false 时,则停止执行计算 。
1959+ - `anyMatch(Predicate )`:如果流中的任意一个元素根据提供的 ** Predicate ** 返回 true 时,结果返回为 true 。在第一个 false 是停止执行计算 。
1960+ - `noneMatch(Predicate )`:如果流的每个元素根据提供的 ** Predicate ** 都返回 false 时,结果返回为 true 。在第一个 true 时停止执行计算 。
19611961
1962- 你已经在 `Prime . java` 中看到了 `noneMatch()` 的示例;` allMatch()` 和 `anyMatch()` 的用法基本上是等同的。让我们探究短路行为。为了创建消除冗余代码的 ` show()` 方法,我们必须首先发现如何统一地描述所有三个匹配器操作,然后将其转换为称作 ** Matcher ** 的接口 :
1962+ 我们已经在 `Prime . java` 中看到了 `noneMatch()` 的示例;`allMatch()` 和 `anyMatch()` 的用法基本上是等同的。下面我们来探究一下短路行为。为了消除冗余代码,我们创建了 ` show()`。首先我们必须治到如何统一地描述这三个匹配器的操作,然后再将其转换为 ** Matcher ** 接口。代码示例 :
19631963
19641964```java
19651965// streams/Matching.java
@@ -2001,15 +2001,17 @@ public class Matching {
200120011 2 3 4 5 6 7 8 9 true
20022002```
20032003
2004- ** BiPredicate ** 是一个二元谓词,这意味着它只能接受两个参数并且只返回 true 或者 false 。它的第一个参数是我们要测试的流,第二个参数是一个谓词 ** Predicate ** 。因为 ** Matcher ** 适用于所有的 ** Stream :: * Match ** 方法形式 ,所以我们可以传递每一个到 `show()` 中。`match. test()` 的调用会被转换成 ** Stream :: * Match ** 函数的调用。
2004+ ** BiPredicate ** 是一个二元断言,它只能接受两个参数且只返回 true 或者 false 。它的第一个参数是我们要测试的流,第二个参数是一个断言 ** Predicate ** 。** Matcher ** 适用于所有的 ** Stream :: \ * Match ** 方法 ,所以我们可以传递每一个到 `show()` 中。`match. test()` 的调用会被转换成 ** Stream :: \ * Match ** 函数的调用。
20052005
2006- `show()` 获取两个参数,** Matcher ** 匹配器和用于表示谓词测试 ** n < val** 中最大值的 ** val** 。这个方法生成一个从 1 到 9 的整数流 。`peek()` 是用于向我们展示测试在短路之前的情况。你可以在输出中发现每一次短路都会发生 。
2006+ `show()` 获取两个参数,** Matcher ** 匹配器和用于表示断言测试 ** n < val** 中最大值的 ** val** 。这个方法生成一个 1 - 9 之间的整数流 。`peek()` 是用于向我们展示测试在短路之前的情况。从输出中可以看到每次都发生了短路 。
20072007
2008- ### 元素查找
2008+ ### 查找
20092009
2010- - `findFirst()`:返回一个含有第一个流元素的 ** Optional ** ,如果流为空返回 ** Optional . empty** 。
2010+ - `findFirst()`:返回第一个流元素的 ** Optional ** ,如果流为空返回 ** Optional . empty** 。
20112011- `findAny(`:返回含有任意流元素的 ** Optional ** ,如果流为空返回 ** Optional . empty** 。
20122012
2013+ 代码示例:
2014+
20132015```java
20142016// streams/SelectElement.java
20152017import java. util. * ;
@@ -2038,7 +2040,7 @@ public class SelectElement {
20382040
20392041`findFirst()` 无论流是否为并行化的,总是会选择流中的第一个元素。对于非并行流,`findAny()`会选择流中的第一个元素(即使从定义上来看是选择任意元素)。在这个例子中,我们使用 `parallel()` 来并行流从而引入 `findAny()` 选择非第一个流元素的可能性。
20402042
2041- 如果必须选择流中最后一个元素,那就使用 ` reduce()`:
2043+ 如果必须选择流中最后一个元素,那就使用 `reduce()`。代码示例 :
20422044
20432045```java
20442046// streams/LastElement.java
@@ -2076,7 +2078,7 @@ three
20762078- `max(Comparator )`:根据所传入的 ** Comparator ** 所决定的“最大”元素。
20772079- `min(Comparator )`:根据所传入的 ** Comparator ** 所决定的“最小”元素。
20782080
2079- 字符串类型有预先定义好的 ** Comparator ** ,这简化了我们的示例 :
2081+ ** String ** 类型有预设的 ** Comparator ** 实现。代码示例 :
20802082
20812083```java
20822084// streams/Informational.java
@@ -2113,9 +2115,9 @@ you
21132115### 数字流信息
21142116
21152117- `average()` :求取流元素平均值。
2116- - `max()` 和 `min()`:因为这些操作在数字流上面,所以不需要 ** Comparator ** 。
2118+ - `max()` 和 `min()`:数值流操作无需 ** Comparator ** 。
21172119- `sum()`:对所有流元素进行求和。
2118- - `summaryStatistics()`:生成可能有用的数据。目前还不太清楚他们为什么觉得有必要这样做,因为你可以使用直接的方法产生所有的数据 。
2120+ - `summaryStatistics()`:生成可能有用的数据。目前并不太清楚这个方法存在的必要性,因为我们其实可以用更直接的方法获得需要的数据 。
21192121
21202122```java
21212123// streams/NumericStreamInfo.java
@@ -2142,11 +2144,11 @@ public class NumericStreamInfo {
21422144IntSummaryStatistics {count= 100 , sum= 50794 , min= 8 , average= 507.940000 , max= 998 }
21432145```
21442146
2145- 这些操作对于 ** LongStream ** 和 ** DoubleStream ** 也同样适用 。
2147+ 上例操作对于 ** LongStream ** 和 ** DoubleStream ** 同样适用 。
21462148
21472149## 本章小结
21482150
2149- 流改变并极大地提升了 Java 编程的性质 ,并可能极大地阻止了 Java 编程人员向诸如 Scala 这种函数式语言的流动 。在本书的剩余部分,我们将尽可能地使用流。
2151+ 流式操作改变并极大地提升了 Java 语言的可编程性 ,并可能极大地阻止了 Java 编程人员向诸如 Scala 这种函数式语言的流转 。在本书的剩余部分,我们将尽可能地使用流。
21502152
21512153< ! -- 分页 -- >
21522154
0 commit comments