@@ -443,6 +443,167 @@ Bubble(4)
443443
444444### iterate()
445445
446+ **Stream.iterate()** 以种子(第一个参数)开头,并将其传给方法(第二个参数)。方法的结果将添加到流,并存储作为第一个参数用于下次调用 **iterate()**,依次类推。我们可以使用 **iterate()** 用于生成一个 Fibonacci 序列(你在上一章中遇到):
447+
448+ ```java
449+ // streams/Fibonacci.java
450+ import java.util.stream.*;
451+ public class Fibonacci {
452+ int x = 1;
453+
454+ Stream<Integer> numbers() {
455+ return Stream.iterate(0, i -> {
456+ int result = x + i;
457+ x = i;
458+ return result;
459+ });
460+ }
461+
462+ public static void main(String[] args) {
463+ new Fibonacci().numbers()
464+ .skip(20) // Don't use the first 20
465+ .limit(10) // Then take 10 of them
466+ .forEach(System.out::println);
467+ }
468+ }
469+ ```
470+
471+ 输出为:
472+
473+ ```java
474+ 6765
475+ 10946
476+ 17711
477+ 28657
478+ 46368
479+ 75025
480+ 121393
481+ 196418
482+ 317811
483+ 514229
484+ ```
485+
486+ Fibonacci 序列将序列中最后两个元素进行求和以产生下一个元素。**iterate()** 只能记忆结果,因此我们需要使用一个变量 **x** 来用于追踪另外一个元素。
487+
488+ 在 **main()** 中,我们使用了一个你之前没有见过的 **skip() ** 操作。它只是根据它的参数丢弃指定数量的流元素。在这里,我们丢弃了前 20 个元素。
489+
490+ ### Stream Builders
491+
492+ 在建造者设计模式中,首先创建一个 builder 对象,传递给它多个构造器信息,最后执行“构造”。**Stream** 库提供了这样的 **Builder**。在这里,我们重新审视读取文件并将其转换成为单词流的过程:
493+
494+ ```java
495+ // streams/FileToWordsBuilder.java
496+ import java.io.*;
497+ import java.nio.file.*;
498+ import java.util.stream.*;
499+
500+ public class FileToWordsBuilder {
501+ Stream.Builder<String> builder = Stream.builder();
502+
503+ public FileToWordsBuilder(String filePath) throws Exception {
504+ Files.lines(Paths.get(filePath))
505+ .skip(1) // Skip the comment line at the beginning
506+ .forEach(line -> {
507+ for (String w : line.split(" [ . ? ,]+ " ))
508+ builder.add(w);
509+ });
510+ }
511+
512+ Stream<String> stream() {
513+ return builder.build();
514+ }
515+
516+ public static void main(String[] args) throws Exception {
517+ new FileToWordsBuilder(" Cheese . dat" )
518+ .stream()
519+ .limit(7)
520+ .map(w -> w + " " )
521+ .forEach(System.out::print);
522+ }
523+ }
524+ ```
525+
526+ 输出为:
527+
528+ ```java
529+ Not much of a cheese shop really
530+ ```
531+
532+ 注意,构造器会添加文件中的所有单词(除了第一行,它是包含文件路径信息的注释),但是其并没有调用 **build()** 方法。这意味着,只要你不调用 **stream()** 方法,就可以继续向 **builder** 对象中添加单词。
533+
534+ 在此类的更完整的版本中,你可以添加一个标志位用于查看 **build()** 方法是否被调用,并且可能的话增加一个可以添加更多单词的方法。在 **Stream.Builder** 调用 **build()** 方法后继续尝试添加单词会产生一个异常。
535+
536+ ### Arrays
537+
538+ **Arrays** 类中含有一个名为 **stream()** 的静态方法用于把数组转换成为流。我们可以重写 **interfaces/Machine.java** 中的 **main()** 方法用于创建一个流,并将 **execute()** 应用于每一个元素:
539+
540+ ```java
541+ // streams/Machine2.java
542+ import java.util.*;
543+ import onjava.Operations;
544+ public class Machine2 {
545+ public static void main(String[] args) {
546+ Arrays.stream(new Operations[] {
547+ () -> Operations.show(" Bing " ),
548+ () -> Operations.show(" Crack " ),
549+ () -> Operations.show(" Twist " ),
550+ () -> Operations.show(" Pop " )
551+ }).forEach(Operations::execute);
552+ }
553+ }
554+ ```
555+
556+ 输出为:
557+
558+ ```java
559+ Bing
560+ Crack
561+ Twist
562+ Pop
563+ ```
564+
565+ **new Operations[]** 表达式动态创建了 **Operations** 对象的数组。
566+
567+ **stream()** 方法同样可以产生 **IntStream**,**LongStream** 和 **DoubleStream**。
568+
569+ ```java
570+ // streams/ArrayStreams.java
571+ import java.util.*;
572+ import java.util.stream.*;
573+
574+ public class ArrayStreams {
575+ public static void main(String[] args) {
576+ Arrays.stream(new double[] { 3.14159, 2.718, 1.618 })
577+ .forEach(n -> System.out.format(" % f " , n));
578+ System.out.println();
579+
580+ Arrays.stream(new int[] { 1, 3, 5 })
581+ .forEach(n -> System.out.format(" % d " , n));
582+ System.out.println();
583+
584+ Arrays.stream(new long[] { 11, 22, 44, 66 })
585+ .forEach(n -> System.out.format(" % d " , n));
586+ System.out.println();
587+
588+ // Select a subrange:
589+ Arrays.stream(new int[] { 1, 3, 5, 7, 15, 28, 37 }, 3, 6)
590+ .forEach(n -> System.out.format(" % d " , n));
591+ }
592+ }
593+ ```
594+
595+ 输出为:
596+
597+ ```java
598+ 3.141590 2.718000 1.618000
599+ 1 3 5
600+ 11 22 44 66
601+ 7 15 28
602+ ```
603+
604+ 最后一次 **stream()** 的调用有两个额外的参数。第一个参数告诉 **stream()** 从哪里开始在数组中选择元素,第二个参数用于告知在哪里停止。每种不同类型的 **stream()** 方法都有这个版本。
605+
606+ ### 正则表达式(Regular Expressions)
446607
447608
448609
0 commit comments