更新 Ranges of int 和 generate() 小节

更新 Ranges of int 和 generate() 小节
This commit is contained in:
Joe
2019-04-09 15:52:50 +08:00
committed by GitHub
parent b7d0ee23d3
commit c5f41a699a

View File

@@ -256,9 +256,192 @@ it shop sir the much cheese by conclusion district is
**main()** 中,我们看到了 **Stream.generate()** 的预览版本,它可以把任意 **Supplier\<T\>** 用于生成 **T** 类型的流。
### int 类型的范围Ranges of int
**IntStream** 类提供了 **range()** 方法用于生成整数序列的流。编写循环时,这个方法会更加便利:
```java
// streams/Ranges.java
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:
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()** 操作求和。
注意 **IntStream.range()** 相比 **onjava.Range.range()** 拥有更多的限制。这是由于其可选的第三个参数,后者能够生成步长大于 1 的范围,并且可以从大到小来生成。
为了替换简单的 **for** 循环,这里是一个 **repeat()** 实用程序:
```java
// onjava/Repeat.java
package onjava;
import static java.util.stream.IntStream.*;
public class Repeat {
public static void repeat(int n, Runnable action) {
range(0, n).forEach(i -> action.run());
}
}
```
其产生的循环更加清晰:
```java
// streams/Looping.java
import static onjava.Repeat.*;
public class Looping {
static void hi() {
System.out.println("Hi!");
}
public static void main(String[] args) {
repeat(3, () -> System.out.println("Looping!"));
repeat(2, Looping::hi);
}
}
```
输出为:
```java
Looping!
Looping!
Looping!
Hi!
Hi!
```
在代码中包含并解释 **repeat()** 似乎有些不值得。它似乎是一个相当透明的工具,但它取决于你的团队和公司的运作方式
### generate()
**RandomWords.java****Stream.generate()** 中使用 **Supplier\<T\>**。这里是第二个示例:
```java
// streams/Generator.java
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class Generator implements Supplier<String> {
Random rand = new Random(47);
char[] letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
public String get() {
return "" + letters[rand.nextInt(letters.length)];
}
public static void main(String[] args) {
String word = Stream.generate(new Generator())
.limit(30)
.collect(Collectors.joining());
System.out.println(word);
}
}
```
输出为:
```java
YNZBRNYGCFOWZNTCQRGSEGZMMJMROE
```
使用 **Random.nextInt()** 方法来挑选字母表中的大写字母。**Random.nextInt()** 的参数代表可以接受的最大的随机数范围,所以使用数组边界是经过深思熟虑的。
如果要创建包含相同对象的流,只需要传递一个生成那些对象 **lambda****generate()** 中:
```java
// streams/Duplicator.java
import java.util.stream.*;
public class Duplicator {
public static void main(String[] args) {
Stream.generate(() -> "duplicate")
.limit(3)
.forEach(System.out::println);
}
}
```
输出为:
```java
duplicate
duplicate
duplicate
```
如下是在这个章节中之前例子使用过的 **Bubble** 类。注意它包含了自己的静态生成器(*static generator*)方法。
```java
// streams/Bubble.java
import java.util.function.*;
public class Bubble {
public final int i;
public Bubble(int n) {
i = n;
}
@Override
public String toString() {
return "Bubble(" + i + ")";
}
private static int count = 0;
public static Bubble bubbler() {
return new Bubble(count++);
}
}
```
由于 **bubbler()****Supplier\<Bubble\>** 是接口兼容的,我们可以将其方法引用直接传递给 **Stream.generate()**
```java
// streams/Bubbles.java
import java.util.stream.*;
public class Bubbles {
public static void main(String[] args) {
Stream.generate(Bubble::bubbler)
.limit(5)
.forEach(System.out::println);
}
}
```
输出为:
```java
Bubble(0)
Bubble(1)
Bubble(2)
Bubble(3)
Bubble(4)
```
这是创建单独工厂类( separate factory class的另外一种方式。在很多方面它更加整洁但是这代表着品味和代码组织的问题 - 你总是可以创建一个完全不同的工厂类。
### iterate()