Skip to content

Commit 2835ade

Browse files
authored
# 第十四章 流式编程 ## 流创建部分内容
# 第十四章 流式编程 ## 流创建部分
1 parent c2f99c8 commit 2835ade

1 file changed

Lines changed: 232 additions & 0 deletions

File tree

docs/book/14-Streams.md

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# 第十四章 流式编程
55

66
<!-- Java 8 Stream Support -->
7+
78
## 流支持
89

910
Java 设计者面临着一个难题。他们拥有着一系列已经存在的库,这些库不仅仅在 Java 库本身中所使用,并且被用户编写的数百万行代码中使用。那他们如何将一个全新的流的基本概念融入到已经存在的库中?
@@ -19,8 +20,239 @@ Java 8 中引入的解决方案是在[接口](10-Interfaces.md)中添加 **defau
1920
<!-- Stream Creation -->
2021
## 流创建
2122

23+
你可以通过 **Stream.of()** 很容易的将一组元素转发成为流(**Bubble** 类在之前的章节中已经定义过了):
24+
25+
```java
26+
// streams/StreamOf.java
27+
import java.util.stream.*;
28+
public class StreamOf {
29+
public static void main(String[] args) {
30+
Stream.of(new Bubble(1), new Bubble(2), new Bubble(3))
31+
.forEach(System.out::println);
32+
Stream.of("It's ", "a ", "wonderful ", "day ", "for ", "pie!")
33+
.forEach(System.out::print);
34+
System.out.println();
35+
Stream.of(3.14159, 2.718, 1.618)
36+
.forEach(System.out::println);
37+
}
38+
}
39+
```
40+
41+
输出为:
42+
43+
```java
44+
Bubble(1)
45+
Bubble(2)
46+
Bubble(3)
47+
It's a wonderful day for pie!
48+
3.14159
49+
2.718
50+
1.618
51+
```
52+
53+
除此之外,每个 **Collection** 都可以通过 **stream()** 方法来产生一个流:
54+
55+
```java
56+
// streams/CollectionToStream.java
57+
import java.util.*;
58+
import java.util.stream.*;
59+
public class CollectionToStream {
60+
public static void main(String[] args) {
61+
List<Bubble> bubbles = Arrays.asList(new Bubble(1), new Bubble(2), new Bubble(3));
62+
System.out.println(bubbles.stream()
63+
.mapToint(b -> b.i)
64+
.sum());
65+
66+
Set<String> w = new HashSet<>(Arrays.asList("It's a wonderful day for pie!".split(" ")));
67+
w.stream()
68+
.map(x -> x + " ")
69+
.forEach(System.out::print);
70+
System.out.println();
71+
72+
Map<String, double> m = new HashMap<>();
73+
m.put("pi", 3.14159);
74+
m.put("e", 2.718);
75+
m.put("phi", 1.618);
76+
m.entrySet().stream()
77+
.map(e -> e.getKey() + ": " + e.getValue())
78+
.forEach(System.out::println);
79+
}
80+
}
81+
```
82+
83+
输出为:
84+
85+
```java
86+
6
87+
a pie! It's for wonderful day
88+
phi: 1.618
89+
e: 2.718
90+
pi: 3.14159
91+
```
92+
93+
在创建 **List\<Bubble\>** 对象之后,我们只需要简单的调用所有集合中都有的方法 **stream()**。中间操作 **map()** 会获取流中的所有元素,并且对流中元素应用操作从而产生新的元素,并将其传递到流中。通常情况 **map()** 方法获取对象并产生新的对象,但是这里有特殊版本的方法用于数值类型的流。例如,**mapToInt()** 方法将一个对象流(objects stream)转换成为包含整形数字的 **IntStream**。同样有针对 **Float** 和 **Double** 的类似名字的操作。
94+
95+
我们通过在 **String** 类型上面应用 **split()** - split 方法会根据参数来拆分字符串 - 获取元素用于定义 **w**。稍后你会看到这个参数十分复杂,但是在这里我们只是根据空格来分割字符串。
96+
97+
为了从 **Map** 集合中产生流数据,我们首先调用 **entrySet()** 去产生一个对象流,每个对象都包含一个键以及与其相关联的值。然后调用 **getKey()** 和 **getValue()** 将其分开。
98+
99+
### 随机数流
100+
101+
**Random** 类被一组生成流的方法增强了:
102+
103+
```java
104+
// streams/RandomGenerators.java
105+
import java.util.*;
106+
import java.util.stream.*;
107+
public class RandomGenerators {
108+
public static <T> void show(Stream<T> stream) {
109+
stream
110+
.limit(4)
111+
.forEach(System.out::println);
112+
System.out.println("++++++++");
113+
}
114+
115+
public static void main(String[] args) {
116+
Random rand = new Random(47);
117+
show(rand.ints().boxed());
118+
show(rand.longs().boxed());
119+
show(rand.doubles().boxed());
120+
// Control the lower and upper bounds:
121+
show(rand.ints(10, 20).boxed());
122+
show(rand.longs(50, 100).boxed());
123+
show(rand.doubles(20, 30).boxed());
124+
// Control the stream size:
125+
show(rand.ints(2).boxed());
126+
show(rand.longs(2).boxed());
127+
show(rand.doubles(2).boxed());
128+
// Control the stream size and bounds:
129+
show(rand.ints(3, 3, 9).boxed());
130+
show(rand.longs(3, 12, 22).boxed());
131+
show(rand.doubles(3, 11.5, 12.3).boxed());
132+
}
133+
}
134+
```
135+
136+
输出为:
137+
138+
```java
139+
-1172028779
140+
1717241110
141+
-2014573909
142+
229403722
143+
++++++++
144+
2955289354441303771
145+
3476817843704654257
146+
-8917117694134521474
147+
4941259272818818752
148+
++++++++
149+
0.2613610344283964
150+
0.0508673570556899
151+
0.8037155449603999
152+
0.7620665811558285
153+
++++++++
154+
16
155+
10
156+
11
157+
12
158+
++++++++
159+
65
160+
99
161+
54
162+
58
163+
++++++++
164+
29.86777681078574
165+
24.83968447804611
166+
20.09247112332014
167+
24.046793846338723
168+
++++++++
169+
1169976606
170+
1947946283
171+
++++++++
172+
2970202997824602425
173+
-2325326920272830366
174+
++++++++
175+
0.7024254510631527
176+
0.6648552384607359
177+
++++++++
178+
6
179+
7
180+
7
181+
++++++++
182+
17
183+
12
184+
20
185+
++++++++
186+
12.27872414236691
187+
11.732085449736195
188+
12.196509449817267
189+
++++++++
190+
```
191+
192+
为了消除冗余代码,我创建了一个泛型方法 **show(Stream\<T\> stream)** (在讲解泛型之前就使用这个特性,确实有点作弊,但是回报是值得的)。类型参数 **T** 可以是任何类型,所以这个方法对 **Integer**, **Long** 和 **Double** 类型都生效。但是 **Random** 类只能生成原始数据类型 **int**, **long**, **double** 的流。幸运的是, **boxed()** 流操作将会自动的把基本类型包装成为对应的装箱类型,从而使得 **show()** 能够接受流。
193+
194+
我们可以使用 **Random** 为任意对象集合创建 **Supplier**。如下是一个从文本文件提供 **String** 对象的例子:
195+
196+
```java
197+
// streams/Cheese.dat
198+
Not much of a cheese shop really, is it?
199+
Finest in the district, sir.
200+
And what leads you to that conclusion?
201+
Well, it's so clean.
202+
It's certainly uncontaminated by cheese.
203+
We use the Files class to read all the lines from a file into a
204+
List<String> :
205+
```
206+
207+
```java
208+
// streams/RandomWords.java
209+
import java.util.*;
210+
import java.util.stream.*;
211+
import java.util.function.*;
212+
import java.io.*;
213+
import java.nio.file.*;
214+
public class RandomWords implements Supplier<String> {
215+
List<String> words = new ArrayList<>();
216+
Random rand = new Random(47);
217+
RandomWords(String fname) throws IOException {
218+
List<String> lines = Files.readAllLines(Paths.get(fname));
219+
// Skip the first line:
220+
for (String line : lines.subList(1, lines.size())) {
221+
for (String word : line.split("[ .?,]+"))
222+
words.add(word.toLowerCase());
223+
}
224+
}
225+
public String get() {
226+
return words.get(rand.nextint(words.size()));
227+
}
228+
@Override
229+
public String toString() {
230+
return words.stream()
231+
.collect(Collectors.joining(" "));
232+
}
233+
public static void main(String[] args) throws Exception {
234+
System.out.println(
235+
Stream.generate(new RandomWords("Cheese.dat"))
236+
.limit(10)
237+
.collect(Collectors.joining(" ")));
238+
}
239+
}
240+
```
241+
242+
输出为:
243+
244+
```java
245+
it shop sir the much cheese by conclusion district is
246+
```
247+
248+
249+
250+
251+
252+
22253
23254
<!-- Intermediate Operations -->
255+
24256
## 中间操作
25257
26258

0 commit comments

Comments
 (0)