From b51d7dff39e061941c7a816cedd8313ad76dfb8e Mon Sep 17 00:00:00 2001 From: Joe <736777445@qq.com> Date: Thu, 11 Apr 2019 14:07:25 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E5=8D=81=E5=9B=9B=E7=AB=A0=20iterate(?= =?UTF-8?q?)=20=E3=80=81Stream=20Builders=E3=80=81Arrays=E7=BF=BB=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 第十四章 iterate() 、Stream Builders、Arrays翻译 --- docs/book/14-Streams.md | 161 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/docs/book/14-Streams.md b/docs/book/14-Streams.md index d46b2ad..1f3f7a1 100644 --- a/docs/book/14-Streams.md +++ b/docs/book/14-Streams.md @@ -443,6 +443,167 @@ Bubble(4) ### iterate() +**Stream.iterate()** 以种子(第一个参数)开头,并将其传给方法(第二个参数)。方法的结果将添加到流,并存储作为第一个参数用于下次调用 **iterate()**,依次类推。我们可以使用 **iterate()** 用于生成一个 Fibonacci 序列(你在上一章中遇到): + +```java +// streams/Fibonacci.java +import java.util.stream.*; +public class Fibonacci { + int x = 1; + + Stream numbers() { + return Stream.iterate(0, i -> { + int result = x + i; + x = i; + return result; + }); + } + + public static void main(String[] args) { + new Fibonacci().numbers() + .skip(20) // Don't use the first 20 + .limit(10) // Then take 10 of them + .forEach(System.out::println); + } +} +``` + +输出为: + +```java +6765 +10946 +17711 +28657 +46368 +75025 +121393 +196418 +317811 +514229 +``` + +Fibonacci 序列将序列中最后两个元素进行求和以产生下一个元素。**iterate()** 只能记忆结果,因此我们需要使用一个变量 **x** 来用于追踪另外一个元素。 + +在 **main()** 中,我们使用了一个你之前没有见过的 **skip() ** 操作。它只是根据它的参数丢弃指定数量的流元素。在这里,我们丢弃了前 20 个元素。 + +### Stream Builders + +在建造者设计模式中,首先创建一个 builder 对象,传递给它多个构造器信息,最后执行“构造”。**Stream** 库提供了这样的 **Builder**。在这里,我们重新审视读取文件并将其转换成为单词流的过程: + +```java +// streams/FileToWordsBuilder.java +import java.io.*; +import java.nio.file.*; +import java.util.stream.*; + +public class FileToWordsBuilder { + Stream.Builder builder = Stream.builder(); + + public FileToWordsBuilder(String filePath) throws Exception { + Files.lines(Paths.get(filePath)) + .skip(1) // Skip the comment line at the beginning + .forEach(line -> { + for (String w : line.split("[ .?,]+")) + builder.add(w); + }); + } + + Stream stream() { + return builder.build(); + } + + public static void main(String[] args) throws Exception { + new FileToWordsBuilder("Cheese.dat") + .stream() + .limit(7) + .map(w -> w + " ") + .forEach(System.out::print); + } +} +``` + +输出为: + +```java +Not much of a cheese shop really +``` + +注意,构造器会添加文件中的所有单词(除了第一行,它是包含文件路径信息的注释),但是其并没有调用 **build()** 方法。这意味着,只要你不调用 **stream()** 方法,就可以继续向 **builder** 对象中添加单词。 + +在此类的更完整的版本中,你可以添加一个标志位用于查看 **build()** 方法是否被调用,并且可能的话增加一个可以添加更多单词的方法。在 **Stream.Builder** 调用 **build()** 方法后继续尝试添加单词会产生一个异常。 + +### Arrays + +**Arrays** 类中含有一个名为 **stream()** 的静态方法用于把数组转换成为流。我们可以重写 **interfaces/Machine.java** 中的 **main()** 方法用于创建一个流,并将 **execute()** 应用于每一个元素: + +```java +// streams/Machine2.java +import java.util.*; +import onjava.Operations; +public class Machine2 { + public static void main(String[] args) { + Arrays.stream(new Operations[] { + () -> Operations.show("Bing"), + () -> Operations.show("Crack"), + () -> Operations.show("Twist"), + () -> Operations.show("Pop") + }).forEach(Operations::execute); + } +} +``` + +输出为: + +```java +Bing +Crack +Twist +Pop +``` + +**new Operations[]** 表达式动态创建了 **Operations** 对象的数组。 + +**stream()** 方法同样可以产生 **IntStream**,**LongStream** 和 **DoubleStream**。 + +```java +// streams/ArrayStreams.java +import java.util.*; +import java.util.stream.*; + +public class ArrayStreams { + public static void main(String[] args) { + Arrays.stream(new double[] { 3.14159, 2.718, 1.618 }) + .forEach(n -> System.out.format("%f ", n)); + System.out.println(); + + Arrays.stream(new int[] { 1, 3, 5 }) + .forEach(n -> System.out.format("%d ", n)); + System.out.println(); + + Arrays.stream(new long[] { 11, 22, 44, 66 }) + .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()** 方法都有这个版本。 + +### 正则表达式(Regular Expressions)