@@ -443,6 +443,167 @@ Bubble(4)
443
443
444
444
### iterate()
445
445
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)
446
607
447
608
448
609
0 commit comments