[ISSUE #40]校订 流式编程-流创建

This commit is contained in:
LingCoder
2019-05-03 23:59:16 +08:00
parent 31fda64472
commit 77a0fbcfc3
2 changed files with 141 additions and 138 deletions

View File

@@ -28,7 +28,7 @@ public class Randoms {
输出结果:
```java
```
6
10
13
@@ -63,7 +63,7 @@ public class ImperativeRandoms {
输出结果:
```java
```
[7, 8, 9, 11, 13, 15, 18]
```
@@ -92,7 +92,7 @@ Java 8 采用的解决方案是:在[接口](10-Interfaces.md)中添加被 `def
<!-- Stream Creation -->
## 流创建
你可以通过 `Stream.of()` 很容易将一组元素转化成为流(`Bubble` 类在之前的章节中已经定义过了):
你可以通过 `Stream.of()` 很容易将一组元素转化成为流(`Bubble` 类在之前的章节中已经定义过了):
```java
// streams/StreamOf.java
@@ -112,7 +112,7 @@ public class StreamOf {
输出结果:
```java
```
Bubble(1)
Bubble(2)
Bubble(3)
@@ -152,9 +152,9 @@ public class CollectionToStream {
}
```
输出
输出结果
```java
```
6
a pie! It's for wonderful day
phi: 1.618
@@ -162,15 +162,15 @@ e: 2.718
pi: 3.14159
```
在创建 `List<Bubble>` 对象之后,我们只需要简单调用所有集合中都有的方法 `stream()`。中间操作 `map()` 会获取流中的所有元素,并且对流中元素应用操作从而产生新的元素,并将其传递到流中。通常情况 `map()` 方法获取对象并产生新的对象,但是这里有特殊版本的方法用于数值类型的流。例如,`mapToInt()` 方法将一个对象流objects stream转换成为包含整形数字的 `IntStream`。同样针对 `Float``Double` 类似名字的操作。
在创建 `List<Bubble>` 对象之后,我们只需要简单调用所有集合中都有的 `stream()`。中间操作 `map()` 会获取流中的所有元素,并且对流中元素应用操作从而产生新的元素,并将其传递到流中。通常 `map()` 获取对象并产生新的对象,但是这里有特殊版本的方法用于数值类型的流。例如,`mapToInt()` 方法将一个对象流objects stream转换成为包含整形数字的 `IntStream`。同样针对 `Float``Double` 也有类似名字的操作。
我们通过`String` 类型上面应用 `split()` - split 方法会根据参数来拆分字符串 - 获取元素用于定义 `w`。稍后你会看到这个参数十分复杂,但在这里我们只是根据空格来分割字符串。
我们通过调用字符串的 `split()`(该方法会根据参数来拆分字符串)来获取元素用于定义变量 `w`。稍后你会知道 `split()` 参数可以是十分复杂,但在这里我们只是根据空格来分割字符串。
为了从 `Map` 集合中产生流数据,我们首先调用 `entrySet()` 去产生一个对象流,每个对象都包含一个键以及与其相关联的值。然后调用 `getKey()``getValue()` 将其分开。
为了从 **Map** 集合中产生流数据,我们首先调用 `entrySet()` 去产生一个对象流,每个对象都包含一个 `key` 键以及与其相关联的 `value` 值。然后调用 `getKey()``getValue()` 将其分开。
### 随机数流
`Random` 类被一组生成流的方法增强了:
`Random` 类被一组生成流的方法增强了。代码示例
```java
// streams/RandomGenerators.java
@@ -189,15 +189,15 @@ public class RandomGenerators {
show(rand.ints().boxed());
show(rand.longs().boxed());
show(rand.doubles().boxed());
// Control the lower and upper bounds:
// 控制上标和下标:
show(rand.ints(10, 20).boxed());
show(rand.longs(50, 100).boxed());
show(rand.doubles(20, 30).boxed());
// Control the stream size:
// 控制流大小:
show(rand.ints(2).boxed());
show(rand.longs(2).boxed());
show(rand.doubles(2).boxed());
// Control the stream size and bounds:
// 控制流的大小和角标
show(rand.ints(3, 3, 9).boxed());
show(rand.longs(3, 12, 22).boxed());
show(rand.doubles(3, 11.5, 12.3).boxed());
@@ -205,9 +205,9 @@ public class RandomGenerators {
}
```
输出
输出结果
```java
```
-1172028779
1717241110
-2014573909
@@ -261,21 +261,23 @@ public class RandomGenerators {
++++++++
```
为了消除冗余代码,我创建了一个泛型方法 `show(Stream<T> stream)` (在讲解泛型之前就使用这个特性,确实有点作弊,但是回报是值得的)。类型参数 `T` 可以是任何类型,所以这个方法对 `Integer` `Long``Double` 类型都生效。但是 `Random` 类只能生成原始数据类型 **int** **long** **double** 的流。幸运的是, `boxed()` 流操作将会自动的把基本类型包装成为对应的装箱类型,从而使得 `show()` 能够接受流。
为了消除冗余代码,我创建了一个泛型方法 `show(Stream<T> stream)` (在讲解泛型之前就使用这个特性,确实有点作弊,但是回报是值得的)。类型参数 `T` 可以是任何类型,所以这个方法对 **Integer**、**Long****Double** 类型都生效。但是 **Random** 类只能生成基本类型 **int** **long** **double** 的流。幸运的是, `boxed()` 流操作将会自动的把基本类型包装成为对应的装箱类型,从而使得 `show()` 能够接受流。
我们可以使用 `Random` 为任意对象集合创建 `Supplier`。如下是一个从文本文件提供 `String` 对象的例子
我们可以使用 **Random** 为任意对象集合创建 **Supplier**。如下是一个从文本文件提供字符串对象的例子
```java
Cheese.dat 文件内容:
```
// streams/Cheese.dat
Not much of a cheese shop really, is it?
Finest in the district, sir.
And what leads you to that conclusion?
Well, it's so clean.
It's certainly uncontaminated by cheese.
We use the Files class to read all the lines from a file into a
List<String> :
```
我们通过 **File** 类将 Cheese.dat 文件的所有行读取到 `List<String>` 中。代码示例:
```java
// streams/RandomWords.java
import java.util.*;
@@ -288,7 +290,7 @@ public class RandomWords implements Supplier<String> {
Random rand = new Random(47);
RandomWords(String fname) throws IOException {
List<String> lines = Files.readAllLines(Paths.get(fname));
// Skip the first line:
// 略过第一行
for (String line : lines.subList(1, lines.size())) {
for (String word : line.split("[ .?,]+"))
words.add(word.toLowerCase());
@@ -311,24 +313,24 @@ public class RandomWords implements Supplier<String> {
}
```
输出
输出结果
```java
```
it shop sir the much cheese by conclusion district is
```
在这里你可以看到更为复杂的 `split()` 的使用。在构造器中,每一行都被 `split()` 方法通过空格或者被方括号包裹的任意标点符号进行分割。在结束方括号后面的 `+` 代表「+ 前面的东西可以出现一次或者多次
在这里你可以看到更为复杂的 `split()` 用。在构造器中,每一行都被 `split()` 通过空格或者被方括号包裹的任意标点符号进行分割。在结束方括号后面的 `+` 代表 `+` 前面的东西可以出现一次或者多次。
你将注意到在构造函数中循环体使用命令式编程(外部迭代)。在以后的例子中,你会看到我如何消除这一点。这种旧的形式不是特别糟糕,但是到处使用流会让你觉得更好一些。
我们注意到在构造函数中循环体使用命令式编程(外部迭代)。在以后的例子中,你会看到我如何消除这一点。这种旧的形式不是特别糟糕,但使用流会让你的代码更好一些。
`toString()` `main()` 中你看到了 `collect()` 收集操作,它根据参数来组合所有流中的元素。
`toString()`主方法中你看到了 `collect()` 收集操作,它根据参数来组合所有流中的元素。
当你使用 `Collectors.joining()`,你将会得到一个 `String` 类型的结果,每个元素都根据 `joining()` 的参数来进行分割。还有许多不同的 `Collectors` 用于获取不同的结果。
当你使用 **Collectors.**`joining()`,你将会得到一个 `String` 类型的结果,每个元素都根据 `joining()` 的参数来进行分割。还有许多不同的 `Collectors` 用于获取不同的结果。
`main()` 中,我们看到了 `Stream.generate()` 的预览版本,它可以把任意 `Supplier<T>` 用于生成 `T` 类型的流。
主方法中,我们看到了 **Stream.**`generate()` 的预览版本,它可以把任意 `Supplier<T>` 用于生成 `T` 类型的流。
### int 类型的范围Ranges of int
### int 类型的范围
`IntStream` 类提供了 `range()` 方法用于生成整数序列的流。编写循环时,这个方法会更加便利:
@@ -337,35 +339,35 @@ it shop sir the much cheese by conclusion district is
import static java.util.stream.IntStream.*;
public class Ranges {
public static void main(String[] args) {
// The traditional way:
// 传统方法:
int result = 0;
for (int i = 10; i < 20; i++)
result += i;
System.out.println(result);
// for-in with a range:
// for-in 循环:
result = 0;
for (int i : range(10, 20).toArray())
result += i;
System.out.println(result);
// Use streams:
// 使用流:
System.out.println(range(10, 20).sum());
}
}
```
输出
输出结果
```java
```
145
145
145
```
`main()` 方法中的第一种方式是我们传统编写 `for` 循环的方式。在第二种方,我们使用 `range()` 创建了流并将其转化为数组,然后在 `for-in` 代码块中使用。但是,如果你能像第三种方法全程使用流是好的。在每种情况下,我们对范围中的数字进行求和,并且流中可以很方便的使用 `sum()` 操作求和。
方法中的第一种方式是我们传统编写 `for` 循环的方式第二种方,我们使用 `range()` 创建了流并将其转化为数组,然后在 `for-in` 代码块中使用。但是,如果你能像第三种方法那样全程使用流是好的。我们对范围中的数字进行求和。在流中可以很方便的使用 `sum()` 操作求和。
注意 `IntStream.range()` 相比 `onjava.Range.range()` 拥有更多的限制。这是由于其可选的第三个参数,后者能够生成步长大于 1 的范围,并且可以从大到小来生成。
注意 **IntStream.**`range()` 相比 `onjava.Range.range()` 拥有更多的限制。这是由于其可选的第三个参数,后者允许步长大于 1并且可以从大到小来生成。
为了替换简单的 `for` 循环,这里是一个 `repeat()` 实用程序
实用小功能 `repeat()` 可以用来替换简单的 `for` 循环。代码示例
```java
// onjava/Repeat.java
@@ -394,9 +396,9 @@ public class Looping {
}
```
输出
输出结果
```java
```
Looping!
Looping!
Looping!
@@ -404,11 +406,11 @@ Hi!
Hi!
```
在代码中包含并解释 `repeat()` 似乎有些不值得。它似乎是一个相当透明的工具,但取决于你的团队和公司的运作方式
原则上,在代码中包含并解释 `repeat()` 不值得。诚然它是一个相当透明的工具,但结果取决于你的团队和公司的运作方式
### generate()
`RandomWords.java` `Stream.generate()` 中使用 `Supplier<T>`。这里是第二个示例:
参照 `RandomWords.java` **Stream.**`generate()` 搭配 `Supplier<T>` 使用的例子。代码示例:
```java
// streams/Generator.java
@@ -433,9 +435,9 @@ public class Generator implements Supplier<String> {
}
```
输出
输出结果
```java
```
YNZBRNYGCFOWZNTCQRGSEGZMMJMROE
```
@@ -455,15 +457,15 @@ public class Duplicator {
}
```
输出
输出结果
```java
```
duplicate
duplicate
duplicate
```
如下是在这个章节中之前例子使用过的 `Bubble` 类。注意它包含了自己的静态生成器(*static generator*)方法。
如下是在本章之前例子使用过的 `Bubble` 类。**注意**它包含了自己的静态生成器(Static generator方法。
```java
// streams/Bubble.java
@@ -487,7 +489,7 @@ public class Bubble {
}
```
由于 `bubbler()``Supplier<Bubble>` 是接口兼容的,我们可以将其方法引用直接传递给 `Stream.generate()`
由于 `bubbler()``Supplier<Bubble>` 是接口兼容的,我们可以将其方法引用直接传递给 **Stream.**`generate()`
```java
// streams/Bubbles.java
@@ -501,9 +503,9 @@ public class Bubbles {
}
```
输出
输出结果
```java
```
Bubble(0)
Bubble(1)
Bubble(2)
@@ -511,11 +513,11 @@ Bubble(3)
Bubble(4)
```
这是创建单独工厂类( separate factory class的另一种方式。在很多方面它更加整洁,但是这代表着品味和代码组织的问题 - 你总是可以创建一个完全不同的工厂类。
这是创建单独工厂类(Separate Factory class的另一种方式。在很多方面它更加整洁但是这对于代码组织和品味是个问题——你总是可以创建一个完全不同的工厂类。
### iterate()
`Stream.iterate()` 以种子(第一个参数)开头,并将其传给方法(第二个参数)。方法的结果将添加到流,并存储作为第一个参数用于下次调用 `iterate()`,依次类推。我们可以使`iterate()` 用于生成一个 Fibonacci 序列(你在上一章中遇到)
**Stream.**`iterate()` 以种子(第一个参数)开头,并将其传给方法(第二个参数)。方法的结果将添加到流,并存储作为第一个参数用于下次调用 `iterate()`,依次类推。我们可以`iterate()` 生成一个斐波那契数列。代码示例
```java
// streams/Fibonacci.java
@@ -533,16 +535,16 @@ public class Fibonacci {
public static void main(String[] args) {
new Fibonacci().numbers()
.skip(20) // Don't use the first 20
.limit(10) // Then take 10 of them
.skip(20) // 过滤前 20
.limit(10) // 然后取 10 个
.forEach(System.out::println);
}
}
```
输出
输出结果
```java
```
6765
10946
17711
@@ -555,13 +557,13 @@ public class Fibonacci {
514229
```
Fibonacci 序列将列中最后两个元素进行求和以产生下一个元素。`iterate()` 只能记忆结果,因此我们需要使用一个变量 `x` 来用于追踪另外一个元素。
斐波那契数列将列中最后两个元素进行求和以产生下一个元素。`iterate()` 只能记忆结果,因此我们需要用一个变量 `x` 追踪另外一个元素。
`main()` 中,我们使用了一个之前没有见过的 `skip()` 操作。它只是根据它的参数丢弃指定数量的流元素。在这里,我们丢弃了前 20 个元素。
主方法中,我们使用了一个之前没有见过的 `skip()` 操作。它根据参数丢弃指定数量的流元素。在这里,我们丢弃了前 20 个元素。
### Stream Builders
### 流的建造者模式
在建造者设计模式中,首先创建一个 builder 对象,传递给它多个构造器信息,最后执行“构造”。`Stream` 库提供了这样的 `Builder`。在这里,我们重新审视读取文件并将其转换成为单词流的过程:
在建造者设计模式(也称构造器模式)中,首先创建一个 `builder` 对象,传递给它多个构造器信息,最后执行“构造”。**Stream** 库提供了这样的 `Builder`。在这里,我们重新审视文件读取并将其转换成为单词流的过程。代码示例
```java
// streams/FileToWordsBuilder.java
@@ -574,7 +576,7 @@ public class FileToWordsBuilder {
public FileToWordsBuilder(String filePath) throws Exception {
Files.lines(Paths.get(filePath))
.skip(1) // Skip the comment line at the beginning
.skip(1) // 略过开头的注释行
.forEach(line -> {
for (String w : line.split("[ .?,]+"))
builder.add(w);
@@ -595,19 +597,19 @@ public class FileToWordsBuilder {
}
```
输出
输出结果
```java
```
Not much of a cheese shop really
```
注意,构造器会添加文件中的所有单词(除了第一行,它是包含文件路径信息的注释),但是其并没有调用 `build()` 方法。这意味着,只要你不调用 `stream()` 方法,就可以继续向 `builder` 对象中添加单词。
**注意**,构造器会添加文件中的所有单词(除了第一行,它是包含文件路径信息的注释),但是其并没有调用 `build()`只要你不调用 `stream()` 方法,就可以继续向 `builder` 对象中添加单词。
类的更完整版本中,你可以添加一个标志位用于查看 `build()` 方法是否被调用,并且可能的话增加一个可以添加更多单词的方法。在 `Stream.Builder` 调用 `build()` 方法后继续尝试添加单词会产生一个异常。
类的更完整版本中,你可以添加一个标志位用于查看 `build()` 是否被调用,并且可能的话增加一个可以添加更多单词的方法。在 `Stream.Builder` 调用 `build()` 方法后继续尝试添加单词会产生一个异常。
### Arrays
`Arrays` 类中含有一个名为 `stream()` 的静态方法用于把数组转换成为流。我们可以重写 `interfaces/Machine.java` 中的 `main()` 方法用于创建一个流,并将 `execute()` 应用于每一个元素:
`Arrays` 类中含有一个名为 `stream()` 的静态方法用于把数组转换成为流。我们可以重写 `interfaces/Machine.java` 中的方法用于创建一个流,并将 `execute()` 应用于每一个元素。代码示例
```java
// streams/Machine2.java
@@ -625,9 +627,9 @@ public class Machine2 {
}
```
输出
输出结果
```java
```
Bing
Crack
Twist
@@ -636,7 +638,7 @@ Pop
`new Operations[]` 表达式动态创建了 `Operations` 对象的数组。
`stream()` 方法同样可以产生 `IntStream``LongStream``DoubleStream`
`stream()` 同样可以产生 **IntStream****LongStream**`**DoubleStream**
```java
// streams/ArrayStreams.java
@@ -657,27 +659,27 @@ public class ArrayStreams {
.forEach(n -> System.out.format("%d ", n));
System.out.println();
// Select a subrange:
// 选择一个子域:
Arrays.stream(new int[] { 1, 3, 5, 7, 15, 28, 37 }, 3, 6)
.forEach(n -> System.out.format("%d ", n));
}
}
```
输出
输出结果
```java
```
3.141590 2.718000 1.618000
1 3 5
11 22 44 66
7 15 28
```
最后一次 `stream()` 的调用有两个额外的参数。第一个参数告诉 `stream()` 从哪里开始在数组中选择元素,第二个参数用于告知在哪里停止。每种不同类型的 `stream()` 方法都有这个版本
最后一次 `stream()` 的调用有两个额外的参数。第一个参数告诉 `stream()` 从数组的哪个位置开始选择元素,第二个参数用于告知在哪里停止。每种不同类型的 `stream()` 都有类似的操作
### 正则表达式Regular Expressions
### 正则表达式
Java 的正则表达式已经在[字符串]()这一章节介绍过了。Java 8 在 `java.util.regex.Pattern` 中增加了一个新的方法 `splitAsStream()`这个方法可以根据你所传入的公式将字符序列转化为流。但是这里有一个限制,输入只能是 `CharSequence`,因此不能将流作为 `splitAsStream()` 的参数。
Java 的正则表达式已经在[字符串](18-Strings.md)这一章节介绍过了。Java 8 在 `java.util.regex.Pattern` 中增加了一个新的方法 `splitAsStream()`。这个方法可以根据传入的公式将字符序列转化为流。但是有一个限制,输入只能是 **CharSequence**,因此不能将流作为 `splitAsStream()` 的参数。
我们再一次查看将文件处理为单词流的过程。这一次,我们使用流将文件分割为单独的字符串,接着使用正则表达式将字符串转化为单词流。
@@ -714,19 +716,20 @@ public class FileToWordsRegexp {
}
```
输出
输出结果
```java
```
Not much of a cheese shop really is it
```
在构造器中我们读取了文件中的所有内容(再一次跳过第一行注释,并将其转化成为单行字符串。现在,当你调用 `stream()` 方法的时候,可以像往常一样获取一个流,但这次你可以多次调用 `stream()` 方法,在已存储的字符串中创建一个新的流。这里有个限制,整个文件必须存储在内存中;在大多数情况下这并不是什么问题,但是这损失了流非常重要的好处
在构造器中我们读取了文件中的所有内容(跳过第一行注释,并将其转化成为单行字符串。现在,当你调用 `stream()` 的时候,可以像往常一样获取一个流,但这次你可以多次调用 `stream()` 在已存储的字符串中创建一个新的流。这里有个限制,整个文件必须存储在内存中;在大多数情况下这并不是什么问题,但是这损失了流操作非常重要的优势
1. 流“不需要存储”。当然它们需要一些内部存储,但是这只是序列的一小部分,和持有整个序列所需要的并不相同。
2. 它们是惰性评估的。幸运的是,我们将在稍晚一些的时候查看如何如解决这个问题。
1. 流“不需要存储”。当然它们需要一些内部存储,但是这只是序列的一小部分,和持有整个序列并不相同。
2. 它们是懒加载计算的。
幸运的是,我们稍就会知道如何解决这个问题。
<!-- Intermediate Operations -->
## 中间操作
中间操作用于在一个流中获取元素,并将元素放入另一个流的后端用以连接不同的操作。
@@ -752,9 +755,9 @@ class Peeking {
}
```
输出
输出结果
```java
```
Well WELL well it IT it s S s so SO so
```
@@ -781,9 +784,9 @@ public class SortedComparator {
}
```
输出
输出结果
```java
```
you what to the that sir leads in district And
```
@@ -823,9 +826,9 @@ public class Prime {
}
```
输出
输出结果
```java
```
2 3 5 7 11 13 17 19 23 29
467 479 487 491 499 503 509 521 523 541
```
@@ -879,9 +882,9 @@ class FunctionMap {
}
```
输出
输出结果
```java
```
---( add brackets )---
[12]
[]
@@ -929,9 +932,9 @@ class FunctionMap2 {
}
```
输出
输出结果
```java
```
Numbered(1)
Numbered(5)
Numbered(7)
@@ -966,9 +969,9 @@ class FunctionMap3 {
}
```
输出
输出结果
```java
```
5 7 9
17 19 23
17.000000 1.900000 0.230000
@@ -1005,9 +1008,9 @@ public class StreamOfStreams {
}
```
输出
输出结果
```java
```
java.util.stream.ReferencePipeline$Head
java.util.stream.ReferencePipeline$Head
java.util.stream.ReferencePipeline$Head
@@ -1027,9 +1030,9 @@ public class FlatMap {
}
```
输出
输出结果
```java
```
Gonzo
Fozzie
Beaker
@@ -1060,9 +1063,9 @@ public class StreamOfRandoms {
}
```
输出
输出结果
```java
```
58 -1 55 93 -1 61 61 29 -1 68 0 22 7 -1 88 28 51 89 9 -1
```
@@ -1118,9 +1121,9 @@ public class FileToWordsTest {
}
```
输出
输出结果
```java
```
Not much of a cheese shop really
```
@@ -1167,9 +1170,9 @@ class OptionalsFromEmptyStreams {
}
```
输出
输出结果
```java
```
Optional.empty
Optional.empty
Optional.empty
@@ -1207,9 +1210,9 @@ class OptionalBasics {
}
```
输出
输出结果
```java
```
Epithets
Nothing inside!
```
@@ -1273,9 +1276,9 @@ public class Optionals {
}
```
输出
输出结果
```java
```
=== basics ===
Epithets
Nothing inside!
@@ -1328,9 +1331,9 @@ class CreatingOptionals {
}
```
输出
输出结果
```java
```
=== empty ===
Null
=== of ===
@@ -1387,9 +1390,9 @@ class OptionalFilter {
}
```
输出
输出结果
```java
```
---( true )---
Optional[Foo]
Optional[]
@@ -1478,9 +1481,9 @@ class OptionalMap {
}
```
输出
输出结果
```java
```
---( Add brackets )---
Optional[[12]]
Optional[[]]
@@ -1558,9 +1561,9 @@ class OptionalFlatMap {
}
```
输出
输出结果
```java
```
---( Add brackets )---
Optional[[12]]
Optional[[]]
@@ -1642,7 +1645,7 @@ public class StreamOfOptionals {
}
```
输出
输出结果
```java
Optional[Signal(dash)]
@@ -1727,9 +1730,9 @@ public class ForEach {
}
```
输出
输出结果
```java
```
258 555 693 861 961 429 868 200 522 207 288 128 551 589
551 861 429 589 200 522 555 693 258 128 868 288 961 207
258 555 693 861 961 429 868 200 522 207 288 128 551 589
@@ -1767,9 +1770,9 @@ public class TreeSetOfWords {
}
```
输出
输出结果
```java
```
[Arrays, Collectors, Exception, Files, Output, Paths,
Set, String, System, TreeSet, TreeSetOfWords, args,
class, collect, file, filter, flatMap, get, import,
@@ -1824,9 +1827,9 @@ public class MapCollector {
}
```
输出
输出结果
```java
```
{688=W, 309=C, 293=B, 761=N, 858=N, 668=G, 622=F, 751=N}
```
@@ -1854,9 +1857,9 @@ public class SpecialCollector {
}
```
输出
输出结果
```java
```
cheese
cheese
```
@@ -1900,9 +1903,9 @@ public class Reduce {
}
```
输出
输出结果
```java
```
Frobnitz(58)
Frobnitz(55)
Frobnitz(93)
@@ -1959,9 +1962,9 @@ public class Matching {
}
```
输出
输出结果
```java
```
1 2 3 4 5 6 7 8 9 true
1 2 3 4 false
1 true
@@ -1974,7 +1977,7 @@ public class Matching {
`show()` 获取两个参数,**Matcher** 匹配器和用于表示谓词测试 **n < val** 中最大值的 **val**。这个方法生成一个从 1 到 9 的整数流。`peek()` 是用于像我们展示测试在短路之前的情况。你可以在输出中发现每一次短路都会发生。
### 选择元素Selecting an Element
### 选择元素
- `findFirst()`:返回一个含有第一个流元素的 **Optional**,如果流为空返回 **Optional.empty**。
- `findAny(`:返回含有任意流元素的 **Optional**,如果流为空返回 **Optional.empty**。
@@ -1996,9 +1999,9 @@ public class SelectElement {
}
```
输出
输出结果
```java
```
258
258
258
@@ -2028,9 +2031,9 @@ public class LastElement {
}
```
输出
输出结果
```java
```
19
three
```
@@ -2066,9 +2069,9 @@ public class Informational {
}
```
输出
输出结果
```java
```
32
a
you
@@ -2098,9 +2101,9 @@ public class NumericStreamInfo {
}
```
输出
输出结果
```java
```
507.94
998
8
@@ -2112,8 +2115,7 @@ IntSummaryStatistics{count=100, sum=50794, min=8, average=507.940000, max=998}
## 本章小结
流改变了甚至极大的提升了 Java 编程的性质,并可能极大的组织了 Java 编程人员像诸如 scala 这种函数式语言的流动。在本书的剩余部分,我们将尽可能的使用流。
流改变了甚至极大的提升了 Java 编程的性质,并可能极大的组织了 Java 编程人员像诸如 Scala 这种函数式语言的流动。在本书的剩余部分,我们将尽可能的使用流。
<!-- 分页 -->
<div style="page-break-after: always;"></div>

View File

@@ -7,4 +7,5 @@
| **Aggregation** | 聚合,关联关系的一种,是强的关联关系|
| **Composition** | 组合,关联关系的一种,是比聚合关系强的关系 |
| **STL***the Standard Template Library*| C++ 标准模板库|
| **Fibonacci Sequence**| [斐波那契数列](https://zh.wikipedia.org/wiki/斐波那契数列),又称黄金分割数列 |