【jdk1.8特性】之Stream(上)

筆者日常 Stream知識點真的是…太多了!!!


聲明 由於Stream知識極多,所以本人將其分爲兩個部分進行學習。

Stream(上)主要學習的內容有:
本文所學習的知識
Stream(下)主要學習的內容有:
在這裏插入圖片描述


Stream學習(上)

  • Stream實例的(常用)獲取方法

    • 串行流:
      • Collection.stream()
      • Stream.of(T… values)
      • stream.sequential()
      • Arrays.stream()
      • ……
    • 並行流:
      • Collection.parallelStream()
      • stream.parallel()
    • 相關說明:
      • 串行流由單線程進行處理執行, 並行流由多線程進行處理執行。
      • 在多核的情況下,並行流效率更高。
      • 推薦使用Stream,而不使用顯示迭代(如: for循環等)。
      • 顯示循環、串行流、並行流的性能比較可參考here
      • 串行流、並行流的只是介紹可參考here
      • 在使用並行流時,如果只是用其來處理集合A本身的話,是不會有線程問題的(其內部會自己處理好);如果在使用並行流的時候,涉及到了其他變量B,那麼可能出現線程不安全的情況。 如:listA.parallelStream().map(x -> {listB.add(x); return x;}).forEachOrdered(System.out::print)中,listA的並行流中 進行x -> {listB.add(x); return x;}操作,即:多線程中調用listB的add方法,如果listB是線程不安全的,那麼就可能出現問題。
    • 示例:
      	/**
          * 獲取串行流:
          *     Collection.stream(): 獲取串行Stream
          *     Stream.of(T... values): 獲取串行Stream
          *     stream.sequential(): 獲取串行Stream
          *     Arrays.stream()
          *     ……
          *
          * 獲取並行流:
          *     Collection.parallelStream(): 獲取並行Stream
          *     stream.parallel(): 獲取並行Stream
          *     ……
          *
          * 注:獲取Stream實例的方式方式比較多,這裏只示例了最基本的幾種方式。
          *
          * 相關說明:
          *    1、串行流由單線程進行處理執行, 並行流由多線程進行處理執行。
          *    2、在多核的情況下,並行流效率更高。
          *    3、推薦使用Stream,而不使用顯示迭代(如: for循環等)。
          *    4、顯示循環、串行流、並行流的性能比較可參考<linked>https://blog.csdn.net/java1856905/article/details/88640557</linked>
          *    5、串行流、並行流的只是介紹可參考<linked>https://www.jianshu.com/p/19ffb2c9438a</linked>
          *    6、在使用並行流時,如果只是用其來處理集合A本身的話,是不會有線程問題的(其內部會自己處理好);如果在使用並
          *       行流的時候,涉及到了其他變量B,那麼可能出現線程不安全的情況。 如:
          *       listA.parallelStream()
          *       .map(x -> {listB.add(x); return x;})
          *       .forEachOrdered(x -> System.out.print(x)
          *       中,listA的並行流中 進行x -> {listB.add(x); return x;}操作,
          *       即: 多線程中調用listB的add方法,如果listB是線程不安全的,那麼就可能出現問題。
          */
         @Test
         public void test1() {
             // 數據準備
             List<Staff> tmpList = Lists.newArrayList(
                     Staff.builder().name("張三").age(18).staffNo("NO1").build(),
                     Staff.builder().name("李四").age(25).staffNo("NO2").build(),
                     Staff.builder().name("王五").age(40).staffNo("NO3").build()
             );
         
             /// 獲取串行Stream
             // 常用方式一
             Stream<Staff> stream = tmpList.stream();
             // 常用方式二
             // 這樣:
             // Stream<Staff> stream = Stream.of(a, b, c);
             // 或這樣:
             // Staff[] tmpArray = {a, b, c};
             // Stream<Staff> stream = Stream.of(tmpArray);
             // 或這樣:
             // Arrays.stream()
         
             /// 獲取並行Stream
             // Stream<Staff> stream = tmpList.parallelStream();
             // Stream.of(a, b, c).parallel();
         }
      
  • boolean allMatch(Predicate<? super T> predicate) 是否【所有元素都滿足Predicate】。

  • boolean allMatch(Predicate<? super T> predicate) 是否【存在元素滿足Predicate】。

  • boolean noneMatch(Predicate<? super T> predicate) 是否【所有元素都不滿足Predicate】。

    • 示例:
      /**
       * boolean allMatch: 是否【所有元素都滿足Predicate】
       * boolean anyMatch: 是否【存在元素滿足Predicate】
       * boolean noneMatch: 是否【所有元素都不滿足Predicate】
       */
      @Test
      public void test2() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("張三").age(18).staffNo("NO1").build(),
                  Staff.builder().name("李四").age(25).staffNo("NO2").build(),
                  Staff.builder().name("王五").age(40).staffNo("NO3").build()
          );
          Stream<Staff> stream = tmpList.stream();
      
          // -> Stream.allMatch 測試
          // Predicate<Staff> predicateOne = x -> x.getAge() >= 18;
          // 控制檯輸出true。 即:stream中的所有Staff均滿足predicateOne.
          // System.out.println(stream.allMatch(predicateOne));
      
          // -> Stream.anyMatch 測試
          // Predicate<Staff> predicateTwo = x -> x.getName() != null &&  x.getName().contains("王");
          // 控制檯輸出true。 即:stream中存在Staff滿足 predicateTwo.
          // System.out.println(stream.anyMatch(predicateTwo));
      
          // -> Stream.noneMatch 測試
          Predicate<Staff> predicateThree = x -> "JustryDeng".equals(x.getName());
          // 控制檯輸出true。 即:stream中不存在任何Staff滿足 predicateThree.
          System.out.println(stream.noneMatch(predicateThree));
      }
      
  • static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)創建一個Stream<T>,其元素是:在第一個流的所有元素後再接上第二個流的所有元素。

    • 示例:
      /**
       * static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b): 創建一個String<T>,其元
       *     素是:在第一個流的所有元素後再接上第二個流的所有元素
       */
      @Test
      public void test3() {
          // 基礎數據準備
          Staff a = Staff.builder().name("張三").age(18).staffNo("NO1").build();
          Staff c = Staff.builder().name("王五").age(40).staffNo("NO3").build();
          Stream<Staff> streamA = Stream.of(a, c);
      
          Staff b = Staff.builder().name("李四").age(25).staffNo("NO2").build();
          Stream<Staff> streamB = Stream.of(b);
      
          // 按前後順醋,"拼接"兩個流
          Stream<Staff> stream = Stream.concat(streamA, streamB);
      
          // 輸出:[Staff(name=張三, age=18, staffNo=NO1), Staff(name=王五, age=40, staffNo=NO3), Staff(name=李四, age=25, staffNo=NO2)]
          System.out.println(Arrays.deepToString(stream.toArray()));
      }
      
  • long count()返回此Stream中的元素數量。

    • 示例:
      /**
       * long count: 返回此Stream中的元素數量
       */
      @Test
      public void test4() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("張三").age(18).staffNo("NO1").build(),
                  Staff.builder().name("李四").age(25).staffNo("NO2").build(),
                  Staff.builder().name("王五").age(40).staffNo("NO3").build()
          );
          Stream<Staff> stream = tmpList.stream();
          // 輸出: 3
          System.out.println(stream.count());
      }
      
  • void forEach(Consumer<? super T> action)遍歷元素進行消費。

  • void forEachOrdered(Consumer<? super T> action)有序遍歷元素進行消費。

    • 注:如果是串行流,使用forEach和使用forEachOrdered都能順序消費。如果是並行流,使用forEachOrdered能保證有序消費,而forEach不能保證。
    • 示例:
      /**
       * void forEach(Consumer<? super T> action): 遍歷元素進行消費
       *
       * void forEachOrdered(Consumer<? super T> action): 有序遍歷元素進行消費
       *
       * 注:如果是串行流,使用forEach和使用forEachOrdered都能順序消費。
       *    如果是並行流,使用forEachOrdered能保證有序消費,而forEach不能保證。
       */
      @Test
      public void test6() {
          // 數據準備
          List<Integer> tmpList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9);
      
          // 串行流 forEach
          Stream<Integer> sequentialStreamOne = tmpList.stream();
          // 輸出: 1   2  3  4  5  6  7  8  9
          sequentialStreamOne.forEach(x -> System.out.print(x + "\t"));
          System.out.print("\n");
      
          // 串行流 forEachOrdered
          Stream<Integer> sequentialStreamTwo = tmpList.stream();
          // 輸出: 1   2  3  4  5  6  7  8  9
          sequentialStreamTwo.forEachOrdered(x -> System.out.print(x + "\t"));
          System.out.print("\n");
      
          // 並行流 forEach
          Stream<Integer> parallelStreamOne = tmpList.parallelStream();
          // 輸出: 6   5  7  8  9  2  1  4  3
          parallelStreamOne.forEach(x -> System.out.print(x + "\t"));
          System.out.print("\n");
      
          // 並行流 forEachOrdered
          Stream<Integer> parallelStreamTwo = tmpList.parallelStream();
          // 輸出: 1   2  3  4  5  6  7  8  9
          parallelStreamTwo.forEachOrdered(x -> System.out.print(x + "\t"));
      }
      
  • Stream<T> distinct()根據equals方法去重。

    • 示例:
      /**
       * Stream<T> distinct: 根據equals方法去重。
       */
      @Test
      @SuppressWarnings("all")
      public void test7() {
          String a = "JustryDeng";
          String b = new String("JustryDeng");
          String c = "鄧帥";
          String d = new String("鄧帥");
          // 數據準備
          List<String> tmpList = Lists.newArrayList(a,b, c,d);
          Stream<String> stream = tmpList.parallelStream();
          // 去重
          stream = stream.distinct();
          stream.forEachOrdered(System.out::println);
      }
      
  • Stream<T> filter(Predicate<? super T> predicate)篩選出(只留下)滿足predicate的元素。

    • 示例:
      /**
       * Stream<T> filter(Predicate<? super T> predicate): 篩選出(只留下)滿足predicate的元素。
       */
      @Test
      public void test8() {
          // 數據準備
          List<Integer> tmpList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9);
          Stream<Integer> stream = tmpList.parallelStream();
      
          // 篩選條件
          Predicate<Integer> predicate = x -> x != null && x % 2 == 0;
      
          // 輸出: 2    4 6  8
          stream.filter(predicate).forEachOrdered(x -> System.out.print(x + "\t"));
      }
      
  • Optional<T> findFirst()返回流中的第一個元素的Optional封裝。

    • 注:如果stream是empty,那麼會獲得一個empty的Optional。
    • 注::如果篩選出來的第一個元素爲null,那麼會拋出NPE。
    • 注:If the stream has no encounter order, then any element may be returned.
    • 示例:
      /**
       * Optional<T> findFirst: 返回流中的第一個元素的Optional封裝。
       *
       * 注: 如果stream是empty,那麼會獲得一個empty的Optional。
       * 注: 如果篩選出來的第一個元素爲null,那麼會拋出NPE。
       * 注: If the stream has no encounter order, then any element may be returned.
       */
      @Test
      public void test9() {
          // 數據準備
          List<Integer> tmpList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9);
          Stream<Integer> stream = tmpList.stream();
      
          Optional<Integer> optional = stream.findFirst();
          optional.ifPresent(x -> System.out.println("\t" + x));
      }
      
  • <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)將Stream<T>中的各個元素轉換爲對應的Stream<R>,並用新的Stream<R>替代原來Stream<T>中對應元素的位置,返回一個新的Stream<R>。

    • 注:map與flatMap的都是對原Stream<T>中的元素進行替代。不過map是以一個Object來替代一個T,而flatMap是用一個Stream對象來替代原來的T。
      追注:map與flatMap的主要不同,可以理解爲: map只是以一個Object來替代原來的一個T;而flatMap是以一批(或一個)Object來替代原來的一個T。
    • 示例:
      /**
       * <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper) :
       *     將Stream<T>中的各個元素轉換爲對應的Stream<R>,並用新的Stream<R>替代原
       *     來Stream<T>中對應元素的位置,返回一個新的String<R>
       *
       * 注:map與flatMap的都是對原Stream<T>中的元素進行替代。
       *   不過map是以一個Object來替代一個T,而flatMap是用一個Stream對象來替代原來的T。
       *   追注:map與flatMap的主要不同,可以理解爲: map只是以一個Object來替代原來的一個T;
       *       而flatMap是以一批(或一個)Object來替代原來的一個T;
       */
      @Test
      public void test10() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("張三").age(18).staffNo("NO1").build(),
                  Staff.builder().name("李四").age(25).staffNo("NO2").build(),
                  Staff.builder().name("王五").age(40).staffNo("NO3").build()
          );
      
          // 將元素Staff,轉換爲對應的Stream<String>
          Function<Staff, Stream<String>> function = x -> Arrays.stream(x.getName().split(""));
          // 通過Function<Staff, Stream<String>>,將Stream<Staff>轉換爲Stream<String>
          Stream<Staff> staffStream = tmpList.parallelStream();
          Stream<String> stringStream = staffStream.flatMap(function);
      
          // 輸出: 張   三  李  四  王  五
          stringStream.forEachOrdered(x -> System.out.print(x + "\t"));
      }
      
  • IntStream flatMapToInt(Function<? super T,? extends IntStream> mapper)將當前Stream<T>中的元素T,以對應的(通過Function轉換後得到的)IntStream進行替換,最終返回一個新的IntStream。

  • LongStream flatMapToLong(Function<? super T,? extends LongStream> mapper)將當前Stream<T>中的元素T,以對應的(通過Function轉換後得到的)LongStream進行替換,最終返回一個新的LongStream。

  • DoubleStream flatMapToDouble(Function<? super T,? extends DoubleStream> mapper)將當前Stream<T>中的元素T,以對應的(通過Function轉換後得到的)DoubleStream進行替換,最終返回一個新的DoubleStream。

    • 示例:
      /**
       * IntStream flatMapToInt(Function<? super T,? extends IntStream> mapper) :
       *     將當前Stream<T>中的元素T,以對應的(通過Function轉換後得到的)IntStream進行替換,
       *     最終返回一個新的IntStream。
       *
       * LongStream flatMapToLong(Function<? super T,? extends LongStream> mapper):
       *     將當前Stream<T>中的元素T,以對應的(通過Function轉換後得到的)LongStream進行替換,
       *     最終返回一個新的LongStream。
       *
       * DoubleStream flatMapToDouble(Function<? super T,? extends DoubleStream> mapper) :
       *     將當前Stream<T>中的元素T,以對應的(通過Function轉換後得到的)DoubleStream進行
       *     替換,最終返回一個新的DoubleStream。
       *
       */
      @Test
      public void test11() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("張三").age(18).workStartTimestamp(1234555L).faceScore(99.9D).build(),
                  Staff.builder().name("李四").age(25).workStartTimestamp(2323233L).faceScore(89.2D).build(),
                  Staff.builder().name("王五").age(40).workStartTimestamp(8484848L).faceScore(68.7D).build()
          );
      
          /// flatMapToInt簡單示例
          Stream<Staff> staffStreamOne = tmpList.parallelStream();
          Function<Staff, IntStream> functionOne = x -> IntStream.of(x.getAge());
          IntStream intStream = staffStreamOne.flatMapToInt(functionOne);
          // 輸出: 18  25 40
          intStream.forEachOrdered(x -> System.out.print(x + "\t"));
      
          System.out.println("\n");
      
          /// flatMapToLong簡單示例
          Stream<Staff> staffStreamTwo = tmpList.parallelStream();
          Function<Staff, LongStream> functionTwo = x -> LongStream.of(x.getWorkStartTimestamp());
          LongStream longStream = staffStreamTwo.flatMapToLong(functionTwo);
          // 輸出: 1234555 2323233    8484848
          longStream.forEachOrdered(x -> System.out.print(x + "\t"));
      
          System.out.println("\n");
      
          /// flatMapToDouble簡單示例
          Stream<Staff> staffStreamThree = tmpList.parallelStream();
          Function<Staff, DoubleStream> functionThree = x -> DoubleStream.of(x.getFaceScore());
          DoubleStream doubleStream = staffStreamThree.flatMapToDouble(functionThree);
          // 輸出: 99.9    89.2   68.7
          doubleStream.forEachOrdered(x -> System.out.print(x + "\t"));
      }
      
  • static <T> Stream<T> generate(Supplier<T> s)返回含有無限多個元素的無序的Stream,其中每個元素由提供的Supplier。

    • 注:對比iterate可知,這裏的無序指的是:前一個元素與後一個元素沒有任何關係
    • 注:對於Supplier<T> s,可使用lambda來進行簡化書寫。
    • 注:此方法一般配合limit(long maxSize)進行使用,否則會有無線多個元素。
    • 示例:
      /**
       * static <T> Stream<T> generate(Supplier<T> s):
       *     返回含有無限多個元素的無序的Stream,其中每個元素由提供的Supplier。
       *
       * 注:對比iterate可知,這裏的無序指的是:前一個元素與後一個元素沒有任何關係。
       *
       * 注:對於Supplier<T> s,可使用lambda來進行簡化書寫。
       *
       * 注:此方法一般配合limit(long maxSize)進行使用,否則會有無線多個元素。
       *
       */
      @Test
      public void test12() {
          Stream<Staff> staffStream = Stream.generate(new StaffSupplier()).limit(10);
          staffStream.forEachOrdered(System.out::println);
      
      }
      
      class StaffSupplier implements Supplier<Staff> {
          SecureRandom secureRandom = new SecureRandom();
          @Override
          public Staff get() {
              return Staff.builder()
                      .name("張三")
                      .age(secureRandom.nextInt(200))
                      .workStartTimestamp(Math.abs(secureRandom.nextLong()))
                      .faceScore(secureRandom.nextDouble())
                      .build();
          }
      }
      
  • static <T> Stream iterate(T seed, UnaryOperator<T> f)返回含有無限多個元素的有序的Stream,其中每個元素由提供的Supplier。

    • 注:seed 爲生成的Stream的第一個元素,也是f的起始種子。
    • 注:這裏的有序指的是:後一個元素是由前一個元素根據一定的邏輯產生的。
    • 注:此方法一般配合limit(long maxSize)進行使用,否則會有無線多個元素。
    • 注:流中的元素是否是同一個對象,取決於UnaryOperator的具體實現了。
      一般情況下,最好是使用新的對象。
    • 示例:
      /**
       * static <T> Stream<T> iterate(T seed, UnaryOperator<T> f) :
       *     返回含有無限多個元素的有序的Stream,其中每個元素由提供的Supplier。
       *
       * 注: seed 爲生成的Stream的第一個元素,也是f的起始種子。
       *
       * 注:這裏的有序指的是:後一個元素是由前一個元素根據一定的邏輯產生的。
       *
       * 注:此方法一般配合limit(long maxSize)進行使用,否則會有無線多個元素。
       *
       * 注:流中的元素是否是同一個對象,取決於UnaryOperator的具體實現了。
       *    一般情況下,最好是使用新的對象。
       */
      @Test
      public void test13() {
          Staff foo = Staff.builder().name("張三").age(18).build();
          Stream<Staff> staffStream = Stream.iterate(foo, new StaffOperatorSupplier()).limit(5);
          // 18  19 20 21 22
          staffStream.forEachOrdered(x -> System.out.print(x.getAge() + "\t"));
      
      }
      
      class StaffOperatorSupplier implements UnaryOperator<Staff> {
      
          @Override
          public Staff apply(Staff staff) {
              // System.err.println(staff.hashCode());
              Integer age = staff.getAge();
              age = age == null ? 0 : age + 1;
              return Staff.builder().age(age).build();
          }
      
      }
      
  • Stream<T> limit(long maxSize)截取Stream前面的maxSize個元素。

    • 注:若maxSize大於流的實際長度大小,那麼截取到的元素個數就是流的實際長度大小。
    • 示例:
      /**
       * Stream<T> limit(long maxSize) : 截取Stream前面的maxSize個元素。
       *
       * 注:若maxSize大於流的實際長度大小,那麼截取到的元素個數就是流的實際長度大小。
       */
      @Test
      public void test14() {
          Stream<Integer> parallelStreamOne = Stream.of(1, 2, 3, 4, 5).parallel();
          // 輸出: 123
          parallelStreamOne.limit(3).forEachOrdered(System.out::print);
      
          Stream<Integer> parallelStreamTwo = Stream.of(1, 2, 3, 4, 5).parallel();
          // 輸出: 12345
          parallelStreamTwo.limit(8).forEachOrdered(System.out::print);
      }
      
  • <R> Stream<R> map(Function<? super T,? extends R> mapper)將Stream<T>中的各個元素轉換爲對應的Object,並用新的Object替代原來Stream<T>中對應元素的位置(類型O代替T),返回一個新的Stream<O>。

    • map與flatMap的都是對原Stream<T>中的元素進行替代。不過map是以一個Object來替代一個T,而flatMap是用一個Stream對象來替代原來的T。
      追注:map與flatMap的主要不同,可以理解爲: map只是以一個Object來替代原來的一個T;而flatMap是以一批(或一個)Object來替代原來的一個T。
    • 示例:
      /**
       * <R> Stream<R> map(Function<? super T,? extends R> mapper) :
       *     將Stream<T>中的各個元素轉換爲對應的Object,並用新的Object替代原
       *     來Stream<T>中對應元素的位置(類型O代替T),返回一個新的String<O>。
       *
       * 注:map與flatMap的都是對原Stream<T>中的元素進行替代。
       *   不過map是以一個Object來替代一個T,而flatMap是用一個Stream對象來替代原來的T。
       *   追注:map與flatMap的主要不同,可以理解爲: map只是以一個Object來替代原來的一個T;
       *       而flatMap是以一批(或一個)Object來替代原來的一個T;
       */
      @Test
      public void test15() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("JustryDeng").age(18).staffNo("NO1").build(),
                  Staff.builder().name("鄧沙利文").age(25).staffNo("NO2").build(),
                  Staff.builder().name("鄧二洋").age(40).staffNo("NO3").build()
          );
      
          // 將元素Staff,轉換爲對應的String
          Function<Staff, String> function = x -> x.getName() + "都特麼" + x.getAge() + "歲了!";
          // 通過Function<Staff, String>,將Stream<Staff>轉換爲Stream<String>
          Stream<Staff> staffStream = tmpList.parallelStream();
          Stream<String> stringStream = staffStream.map(function);
      
          // 輸出: JustryDeng都特麼18歲了!  鄧沙利文都特麼25歲了!   鄧二洋都特麼40歲了!
          stringStream.forEachOrdered(x -> System.out.print(x + "\t"));
      }
      
  • IntStream mapToInt(ToIntFunction<? super T> mapper)將當前Stream中的元素T,以對應的(通過Function轉換後得到的)IntStream進行替換,最終返回一個新的IntStream。

  • LongStream mapToLong(ToLongFunction<? super T> mapper)將當前Stream中的元素T,以對應的(通過Function轉換後得到的)LongStream進行替換,最終返回一個新的LongStream。

  • DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper)將當前Stream中的元素T,以對應的(通過Function轉換後得到的)DoubleStream進行替換,最終返回一個新的DoubleStream。

    • 示例:
      /**
       * IntStream mapToInt(ToIntFunction<? super T> mapper):
       *     將當前Stream<T>中的元素T,以對應的(通過Function轉換後得到的)IntStream進行替換,
       *     最終返回一個新的IntStream。
       *
       * LongStream mapToLong(ToLongFunction<? super T> mapper):
       *     將當前Stream<T>中的元素T,以對應的(通過Function轉換後得到的)LongStream進行替換,
       *     最終返回一個新的LongStream。
       *
       * DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper):
       *     將當前Stream<T>中的元素T,以對應的(通過Function轉換後得到的)DoubleStream進行
       *     替換,最終返回一個新的DoubleStream。
       */
      @Test
      public void test16() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("張三").age(18).workStartTimestamp(1234555L).faceScore(99.9D).build(),
                  Staff.builder().name("李四").age(25).workStartTimestamp(2323233L).faceScore(89.2D).build(),
                  Staff.builder().name("王五").age(40).workStartTimestamp(8484848L).faceScore(68.7D).build()
          );
      
          /// mapToInt簡單示例
          Stream<Staff> staffStreamOne = tmpList.parallelStream();
          ToIntFunction<Staff> functionOne = Staff::getAge;
          IntStream intStream = staffStreamOne.mapToInt(functionOne);
          // 輸出: 18  25 40
          intStream.forEachOrdered(x -> System.out.print(x + "\t"));
      
          System.out.println("\n");
      
          /// mapToLong簡單示例
          Stream<Staff> staffStreamTwo = tmpList.parallelStream();
          ToLongFunction<Staff> functionTwo = Staff::getWorkStartTimestamp;
          LongStream longStream = staffStreamTwo.mapToLong(functionTwo);
          // 輸出: 1234555 2323233    8484848
          longStream.forEachOrdered(x -> System.out.print(x + "\t"));
      
          System.out.println("\n");
      
          /// mapToDouble簡單示例
          Stream<Staff> staffStreamThree = tmpList.parallelStream();
          ToDoubleFunction<Staff> functionThree = Staff::getFaceScore;
          DoubleStream doubleStream = staffStreamThree.mapToDouble(functionThree);
          // 輸出: 99.9    89.2   68.7
          doubleStream.forEachOrdered(x -> System.out.print(x + "\t"));
      }
      
  • Optional<T> max(Comparator<? super T> comparator)根據提供的Comparator, 返回此流的最大元素。

  • Optional<T> min(Comparator<? super T> comparator)根據提供的Comparator, 返回此流的最小元素。

    • 示例:
      /**
       * Optional<T> max(Comparator<? super T> comparator): 根據提供的Comparator, 返回此流的最大元素。
       *
       * Optional<T> min(Comparator<? super T> comparator): 根據提供的Comparator, 返回此流的最小元素。
       *
       * 注:對於比較器等,常用lambda表達式進行簡寫優化。
       *
       */
      @Test
      public void test17() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("JustryDeng").age(12).staffNo("NO1").build(),
                  Staff.builder().name("鄧沙利文").age(125).staffNo("NO2").build(),
                  Staff.builder().name("鄧二洋").age(40).staffNo("NO3").build()
          );
      
          /// max示例
          Optional<Staff>  maxOpt= tmpList.stream().parallel().max(new MaxMinStaffComparator());
          // 輸出: Staff(name=鄧沙利文, age=125, staffNo=NO2, faceScore=null, workStartTimestamp=null)
          maxOpt.ifPresent(System.out::println);
      
          /// min示例
          Optional<Staff>  minOpt= tmpList.stream().parallel().min(new MaxMinStaffComparator());
          // 輸出: Staff(name=JustryDeng, age=12, staffNo=NO1, faceScore=null, workStartTimestamp=null)
          minOpt.ifPresent(System.out::println);
      }
      
      class MaxMinStaffComparator implements Comparator<Staff> {
      
          @Override
          public int compare(Staff o1, Staff o2) {
              Objects.requireNonNull(o1);
              Objects.requireNonNull(o2);
              Integer ageOne = o1.getAge();
              Integer ageTwo = o2.getAge();
              Objects.requireNonNull(ageOne);
              Objects.requireNonNull(ageTwo);
              // 注意:這裏比較的順序,會對結果有影響。一般的,都是o1.compareTo(o2);
              //      如果交換比較順序,那麼結果會相反。
              return ageOne.compareTo(ageTwo);
          }
      }
      
  • Stream<T> peek(Consumer<? super T> action)對stream中的元素進行處理,然後返回此Stream。

    • 注:原Stream中的元素對象reference沒變。 但是對象的屬性可能會發生變化。即:這是一箇中間處理操作。
    • 注:對於Consumer接口等的實現,可使用lambda。
    • 示例:
      /**
       * Stream<T> peek(Consumer<? super T> action): 對stream中的元素進行處理,然後返回此Stream。
       *
       * 注:原Stream中的元素對象reference沒變。 但是對象的屬性可能會發生變化。
       *
       * 即:這是一箇中間處理操作。
       *
       * 注:對於Consumer<T>接口等的實現,可使用lambda。
       */
      @Test
      public void test18() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("JustryDeng").age(12).staffNo("NO1").build(),
                  Staff.builder().name("鄧沙利文").age(125).staffNo("NO2").build(),
                  Staff.builder().name("鄧二洋").age(40).staffNo("NO3").build()
          );
          Stream<Staff> stream = tmpList.stream().parallel();
          // 對stream中的元素進行處理
          stream = stream.peek(new PeekConsumer());
          // 輸出:
          //     peek:JustryDeng
          //     peek:鄧沙利文
          //     peek:鄧二洋
          stream.forEachOrdered(x -> System.out.println(x.getName()));
      }
      
      class PeekConsumer implements  Consumer<Staff> {
      
          @Override
          public void accept(Staff staff) {
              staff.setName("peek:" + staff.getName());
          }
      }
      
  • Optional<T> reduce(BinaryOperator<T> accumulator)歸併。通過實現BinaryOperator<T>,Stream<T>中的所有元素,最終歸併爲一個被Optional封裝的T。

    • 說明
    1. 假設:Stream<T>中的元素分別是 T1, T2, T3。
    2. 那麼,先通過BinaryOperator<T>將T1, T2歸併爲 T’, 然後再通過BinaryOperator<T>將前面的歸併結果T’和 T3歸併爲 T",最終將T"封裝進Optional進行返回。
    • 注:推薦使用lambda表達式對BinaryOperator<T>進行實現。
    • 示例:
      /**
       * Optional<T> reduce(BinaryOperator<T> accumulator): 歸併。通過實現BinaryOperator<T>,Stream<T>中的所有
       *                                                    元素,最終歸併爲一個被Optional封裝的T。
       *
       * 假設:Stream<T>中的元素分別是 T1, T2, T3.
       * 那麼:先通過BinaryOperator<T>將T1, T2歸併爲 T', 然後再通過BinaryOperator<T>將
       *      前面的歸併結果T' 和 T3歸併爲 T", 最終將T"封裝進Optional進行返回。
       *
       * 注:推薦使用lambda表達式對BinaryOperator<Staff>進行實現。
       */
      @Test
      public void test19() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("JustryDeng").build(),
                  Staff.builder().name("鄧沙利文").build(),
                  Staff.builder().name("鄧二洋").build()
          );
          Stream<Staff> stream = tmpList.stream().parallel();
          Optional<Staff> opt = stream.reduce(new MyBinaryOperator());
          // 輸出: JustryDeng & 鄧沙利文 & 鄧二洋
          opt.ifPresent(x -> System.out.println(x.getName()));
      }
      
      class MyBinaryOperator implements BinaryOperator<Staff> {
      
          @Override
          public Staff apply(Staff s1, Staff s2) {
              return Staff.builder()
                          .name(s1.getName() + " & " + s2.getName())
                          .build();
          }
      }
      
  • 【串行流】下的T reduce(T identity, BinaryOperator<T> accumulator)使用identity與第一個元素進行歸併得到歸併結果accumulatorT,然後再用accumulatorT與後面的元素進行歸併。

    • 說明
    1. 假設:identity是T0, Stream<T>中的元素分別是 T1, T2, T3。
    2. 那麼,第一步:先將T0, T1歸併爲 tmpT1, 然後再將前面的歸併結果(首次無)與tmpT1歸併爲accumulatorT1。
      注:因爲第一次歸併,所以此時accumulatorT1即爲tmpT1。
    3. 第二步:將accumulatorT1與T2歸併爲accumulatorT2。
    4. 第三步:將accumulatorT2與T3歸併爲accumulatorT3。
    5. 第四步:返回accumulatorT3。
      注:accumulatorT3的類型爲T。
    • 示例:
      /**
       * 【串行流】下的T reduce(T identity, BinaryOperator<T> accumulator): 使用identity與第一個元素
       *   進行歸併得到歸併結果accumulatorT,然後再用accumulatorT與後面的元素進行歸併。
       *
       * 假設:identity是T0, Stream<T>中的元素分別是 T1, T2, T3.
       *
       * 那麼,第一步:先將T0, T1歸併爲 tmpT1, 然後再將前面的歸併結果(首次無)與tmpT1歸併爲accumulatorT1。
       *        注:因爲第一次歸併,所以此時accumulatorT1即爲tmpT1。
       *     第二步:將accumulatorT1與T2歸併爲accumulatorT2。
       *     第三步:將accumulatorT2與T3歸併爲accumulatorT3。
       *     第四步:返回accumulatorT3。
       *           注:accumulatorT3的類型爲T。
       */
      @Test
      public void test20_0() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("JustryDeng").build(),
                  Staff.builder().name("鄧沙利文").build(),
                  Staff.builder().name("鄧二洋").build()
          );
          Stream<Staff> stream = tmpList.stream();
      
          Staff identityStaff = Staff.builder().name("苗苗").build();
          Staff staff = stream.reduce(identityStaff, (s1, s2) -> Staff.builder()
                  .name(s1.getName() + " & " + s2.getName())
                  .build());
          /// 輸出: 苗苗 & JustryDeng & 鄧沙利文 & 鄧二洋
          //  說明: 第一步,accumulatorT1的getName()值爲【苗苗 & JustryDeng】
          //       第二步,accumulatorT2的getName()值爲【苗苗 & JustryDeng & 鄧沙利文】
          //       第三步、第四步,accumulatorT3的getName()值爲【苗苗 & JustryDeng & 鄧沙利文 & 鄧二洋】
          System.out.println(staff.getName());
      }
      
  • 【並行流】下的T reduce(T identity, BinaryOperator<T> accumulator)在並行多線程時,在每個線程內部先使用identity與流的當前元素通過accumulator進行歸併,每個線程都會得到臨時結果resultT,然後再通過accumulator歸併各個線程的resultT,最終歸併爲一個T。

    • 說明
    1. 假設:identity是T0, Stream<T>中的元素分別是 T1, T2, T3。
    2. 那麼,第一步:線程內部的歸併,T0, T1歸併爲 tmpT1, T0, T2歸併爲 tmpT2, T0, T3歸併爲 tmpT3。
    3. 第二步:依次歸併tmpT1、tmpT2、tmpT3。 返回類型爲T的結果。
    • 示例:
      /**
       * 【並行流】下的T reduce(T identity, BinaryOperator<T> accumulator):
       *       在並行多線程時,在每個線程內部先使用identity與流的當前元素通過accumulator進行歸併,
       *       每個線程都會得到臨時結果resultT,
       *       然後再通過accumulator歸併各個線程的resultT,最終歸併爲一個T。
       *
       * 假設:identity是T0, Stream<T>中的元素分別是 T1, T2, T3.
       *
       * 那麼,第一步:線程內部的歸併,T0, T1歸併爲 tmpT1, T0, T2歸併爲 tmpT2, T0, T3歸併爲 tmpT3。
       *     第二步:依次歸併tmpT1、tmpT2、tmpT3。 返回類型爲T的結果。
       */
      @Test
      public void test20_1() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("JustryDeng").build(),
                  Staff.builder().name("鄧沙利文").build(),
                  Staff.builder().name("鄧二洋").build()
          );
          Stream<Staff> stream = tmpList.stream().parallel();
      
          Staff identityStaff = Staff.builder().name("苗苗").build();
          Staff staff = stream.reduce(identityStaff, (s1, s2) -> Staff.builder()
                                                                      .name(s1.getName() + " & " + s2.getName())
                                                                      .build());
          /// 輸出: 苗苗 & JustryDeng & 苗苗 & 鄧沙利文 & 苗苗 & 鄧二洋
          //  說明: 第一步,線程內部的歸併,得到【苗苗 & JustryDeng】、【苗苗 & 鄧沙利文】、【苗苗 & 鄧二洋】
          //       第二步,歸併各個線程結果, 得到【苗苗 & JustryDeng & 苗苗 & 鄧沙利文 & 苗苗 & 鄧二洋】
          System.out.println(staff.getName());
      }
      
  • 【串行流】下的 <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)先使用identity(類型爲U)與流的第一個元素(類型爲T)通過accumulator進行歸併,得到臨時結果resultU(類型爲U),然後再通過accumulator歸併前面的歸併結果resultU(類型爲U)與流後面的元素(類型爲T)逐個歸併。最終歸併爲一個 U。

    • 說明
    1. 假設:identity是U0, Stream<T>中的元素分別是 T1, T2, T3。
    2. 那麼,第一步:將U0, T1通過accumulator歸併爲 resultU1。
    3. 第二步:將resultU1, T2通過accumulator歸併爲 resultU2。
    4. 第三步:將resultU2, T3通過accumulator歸併爲 resultU3。
    5. 第四步:返回resultU3。
    • 注:流的類型爲T。 返回的類型U可以是任何類型(包括類型T)。
    • 注:串行流下,第三個參數combiner不生效。
    • 示例:
      /**
       * 【串行流】下的 <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner):
       *       先使用identity(類型爲U)與流的第一個元素(類型爲T)通過accumulator進行歸併,得到臨時結果resultU(類型爲U),
       *       然後再通過accumulator歸併前面的歸併結果resultU(類型爲U)與流後面的元素(類型爲T)逐個歸併。最終歸併爲一個U。
       *
       * 假設:identity是U0, Stream<T>中的元素分別是 T1, T2, T3.
       *
       * 那麼,第一步:將U0, T1通過accumulator歸併爲 resultU1。
       *     第二步:將resultU1, T2通過accumulator歸併爲 resultU2。
       *     第二步:將resultU2, T3通過accumulator歸併爲 resultU3。
       *     第四步:返回resultU3。
       *
       * 注:流的類型爲T。 返回的類型U可以是任何類型(包括類型T)。
       *
       * 注:串行流下,第三個參數combiner不生效。
       */
      @Test
      public void test21_0() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("JustryDeng").build(),
                  Staff.builder().name("鄧沙利文").build(),
                  Staff.builder().name("鄧二洋").build()
          );
          Stream<Staff> stream = tmpList.stream();
      
          Staff identityStaff = Staff.builder().name("苗苗").build();
          Staff staff = stream.reduce(identityStaff,
                  (p1, p2) -> Staff.builder().name(p1.getName() + " | " + p2.getName()).build(),
                  (s1, s2) -> Staff.builder().name(s1.getName() + " & " + s2.getName()).build());
          /// 輸出: 苗苗 | JustryDeng | 鄧沙利文 | 鄧二洋
          //  說明: 第一步,resultU1的getName()值爲【苗苗 | JustryDeng】
          //       第二步,resultU2的getName()值爲【苗苗 | JustryDeng | 鄧沙利文】
          //       第三步、第四步,resultU3的getName()值爲【苗苗 | JustryDeng | 鄧沙利文 | 鄧二洋】
          System.out.println(staff.getName());
      }
      
  • 【並行流】下的 <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)在並行多線程時,在每個線程內部先使用identity(類型爲U)與流的當前元素(類型爲T)通過accumulator進行歸併,每個線程都會得到臨時結果resultU(類型爲U),然後再通過combiner歸併各個線程的resultU(類型爲U),最終歸併爲一個U。

    • 說明
    1. 假設:identity是U0, Stream<T>中的元素分別是 T1, T2, T3。
    2. 那麼,第一步:線程內部的歸併,U0, T1歸併爲 tmpU1, U0, T2歸併爲 tmpU2, U0, T3歸併爲 tmpU3。
    3. 第二步:依次歸併tmpU1、tmpU2、tmpU3。 返回類型爲U的結果。
    • 注:流的類型爲T。 返回的類型U可以是任何類型(包括類型T)。
    • 注:並行流下,第三個參數combiner生效,用於歸併各個線程的結果。
    • 示例:
      /**
       * 【並行流】下的 <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner):
       *       在並行多線程時,在每個線程內部先使用identity(類型爲U)與流的當前元素(類型爲T)通過accumulator進行歸併,
       *       每個線程都會得到臨時結果resultU(類型爲U),
       *       然後再通過combiner歸併各個線程的resultU(類型爲U),最終歸併爲一個U。
       *
       * 假設:identity是U0, Stream<T>中的元素分別是 T1, T2, T3.
       *
       * 那麼,第一步:線程內部的歸併,U0, T1歸併爲 tmpU1, U0, T2歸併爲 tmpU2, U0, T3歸併爲 tmpU3。
       *     第二步:依次歸併tmpU1、tmpU2、tmpU3。 返回類型爲U的結果。
       *
       * 注:流的類型爲T。 返回的類型U可以是任何類型(包括類型T)。
       *
       * 注:並行流下,第三個參數combiner生效,用於歸併各個線程的結果。
       */
      @Test
      public void test21_1() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("JustryDeng").build(),
                  Staff.builder().name("鄧沙利文").build(),
                  Staff.builder().name("鄧二洋").build()
          );
          Stream<Staff> stream = tmpList.stream().parallel();
      
          Staff identityStaff = Staff.builder().name("苗苗").build();
          Staff staff = stream.reduce(identityStaff,
                  (p1, p2) -> Staff.builder().name(p1.getName() + " | " + p2.getName()).build(),
                  (s1, s2) -> Staff.builder().name(s1.getName() + " & " + s2.getName()).build());
          /// 輸出: 苗苗 | JustryDeng & 苗苗 | 鄧沙利文 & 苗苗 | 鄧二洋
          //  說明: 第一步,線程內部的歸併,得到【苗苗 | JustryDeng】、【苗苗 | 鄧沙利文】、【苗苗 | 鄧二洋】
          //       第二步,歸併各個線程結果, 得到【苗苗 | JustryDeng & 苗苗 | 鄧沙利文 & 苗苗 | 鄧二洋】
          System.out.println(staff.getName());
      }
      
  • 示例reduce方法U與T類型不同的情況

    • 示例:
      /**
       * 示例
       * <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)方法中,
       * U與T類型不同的情況
       */
      @Test
      public void test21_2() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("JustryDeng").build(),
                  Staff.builder().name("鄧沙利文").build(),
                  Staff.builder().name("鄧二洋").build()
          );
      
          /// -> 串行流下 U與T類型不同的情況 (以List<String>爲U, 以Staff爲T)示例
          Stream<Staff> streamOne = tmpList.stream();
          List<String> identityOne = new ArrayList<>(3);
          // 串行流下,線程安全,引入“第三方”時,可不考慮其是否線程安全(如:這裏直接使用ArrayList的add方法)。
          List<String> resultOne = streamOne.reduce(
                  identityOne,
                  (List<String> p1, Staff p2) -> {
                      p1.add(p2.getName());
                      return p1;
                  },
                  (x1, x2) -> x1);
          /// 輸出: [JustryDeng, 鄧沙利文, 鄧二洋]
          System.out.println(resultOne);
      
      
          /// -> 並行流下 U與T類型不同的情況 (以List<String>爲U, 以Staff爲T)示例
          Stream<Staff> streamTwo = tmpList.stream().parallel();
          // 涉及到多線程時,相關位置注意要使用線程安全的類。
          List<String> identityTwo = new CopyOnWriteArrayList<>();
          // 或者: List<String> identityTwo = Collections.synchronizedList(new ArrayList<>(3));
          List<String> resultTwo = streamTwo.reduce(
                  identityTwo,
                  // 此時p1類型實際爲CopyOnWriteArrayList,在多線程情況下,是安全的。
                  (List<String> p1, Staff p2) -> {
                      p1.add(p2.getName());
                      return p1;
                  },
                  // 在併發的情況下,我們已經使用了CopyOnWriteArrayList保證線程安全,且在第二個參數處做了累加操作,
                  // 那麼在這裏(第三個參數)即可什麼也不作。 當然也可以讓累加操作在這兒離進行
                  (List<String> x1, List<String> x2) -> x2);
          /// 輸出: [鄧沙利文, 鄧二洋, JustryDeng]
          System.out.println(resultTwo);
      }
      
  • Stream<T> skip(long n)丟棄前面n個元素, 返回剩下的元素流。

    • 注:若流的元素個數 <= n,那麼丟棄後,將返回一個空的流。
    • 示例:
      /**
       * Stream<T> skip(long n): 前面n個元素, 返回剩下的元素流。
       *
       * 注:若流的元素個數 <= n,那麼丟棄後,將返回一個空的流。
       */
      @Test
      public void test22() {
          Stream<Integer> parallelStreamOne = Stream.of(1, 2, 3, 4, 5).parallel();
          Stream<Integer> remainStreamOne = parallelStreamOne.skip(3L);
          // 輸出:  > 4 > 5
          remainStreamOne.forEachOrdered(x -> System.out.print(" > " + x));
      
      
          Stream<Integer> parallelStreamTwo = Stream.of(1, 2, 3, 4, 5).parallel();
          Stream<Integer> remainStreamTwo = parallelStreamTwo.skip(5L);
          // 輸出:
          // 注;流爲空,都不會進入循環,所以不會輸出任何東西
          remainStreamTwo.forEachOrdered(x -> System.out.print(" > " + x));
      
      
          Stream<Integer> parallelStreamThree = Stream.of(1, 2, 3, 4, 5).parallel();
          Stream<Integer> remainStreamThree = parallelStreamThree.skip(6L);
          // 輸出:
          // 注;流爲空,都不會進入循環,所以不會輸出任何東西
          remainStreamThree.forEachOrdered(x -> System.out.print(" > " + x));
      }
      
  • Stream<T> sorted()對流元素進行自然排序(ASC2碼排序)。

    • 示例:
      /**
       * Stream<T> sorted(): 對流元素進行自然排序(ASC2碼排序)。
       */
      @Test
      public void test23() {
          /*
           * b 的ASC2爲 98
           * # 的ASC2爲 35
           * a 的ASC2爲 97
           * % 的ASC2爲 37
           * ! 的ASC2爲 33
           */
          Stream<Character> parallelStreamOne = Stream.of('b', '#', 'a', '%', '!').parallel();
          parallelStreamOne = parallelStreamOne.sorted();
          // 輸出: > ! > # > % > a > b
          parallelStreamOne.forEachOrdered(x -> System.out.print(" > " + x));
      
          /*
           * 趙 的ASC2爲 36213
           * 錢 的ASC2爲 38065
           * 孫 的ASC2爲 23385
           * 李 的ASC2爲 26446
           */
          System.out.println();
          Stream<String> parallelStreamTwo = Stream.of("趙", "錢", "孫", "李").parallel();
          parallelStreamTwo = parallelStreamTwo.sorted();
          // 輸出: > 孫 > 李 > 趙 > 錢
          parallelStreamTwo.forEachOrdered(x -> System.out.print(" > " + x));
      
          // ASC2碼值
          // System.out.println((int) "趙".charAt(0));
          // System.out.println((int) "錢".charAt(0));
          // System.out.println((int) "孫".charAt(0));
          // System.out.println((int) "李".charAt(0));
      }
      
  • Stream<T> sorted(Comparator<? super T> comparator)根據比較器,對流元素進行排序。

    • 示例:
      /**
       * Stream<T> sorted(Comparator<? super T> comparator): 根據比較器,對流元素進行排序。
       */
      @Test
      public void test24() {
          Stream<String> parallelStream = Stream.of("李d", "錢b", "孫c", "趙a").parallel();
          parallelStream = parallelStream.sorted((String a, String b) -> {
              char aChar = a.charAt(a.length() - 1);
              char bChar = b.charAt(b.length() - 1);
              return Character.compare(aChar, bChar);
          });
          // 輸出:  > 趙a > 錢b > 孫c > 李d
          parallelStream.forEachOrdered(x -> System.out.print(" > " + x));
      }
      
  • Object[] toArray()流轉Object數組。

    • 示例:
      /**
       * Object[] toArray(): 流轉Object數組。
       */
      @Test
      public void test25() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("JustryDeng").build(),
                  Staff.builder().name("鄧沙利文").build(),
                  Staff.builder().name("鄧二洋").build()
          );
          Object[] array = tmpList.parallelStream().toArray();
          // 輸出: [
          //       Staff(name=JustryDeng, age=null, staffNo=null, faceScore=null, workStartTimestamp=null),
          //       Staff(name=鄧沙利文, age=null, staffNo=null, faceScore=null, workStartTimestamp=null),
          //       Staff(name=鄧二洋, age=null, staffNo=null, faceScore=null, workStartTimestamp=null)
          //       ]
          System.out.println(Arrays.deepToString(array));
      }
      
  • <A> A[] toArray(IntFunction<A[]> generator)流轉指定類型的數組。

    • 示例:
      /**
       * <A> A[] toArray(IntFunction<A[]> generator): 流轉指定類型的數組。
       */
      @Test
      public void test26() {
          // 數據準備
          List<Staff> tmpList = Lists.newArrayList(
                  Staff.builder().name("JustryDeng").build(),
                  Staff.builder().name("鄧沙利文").build(),
                  Staff.builder().name("鄧二洋").build()
          );
          Stream<Staff> stream = tmpList.parallelStream();
          // 流轉指定類型的數組
          IntFunction<Staff[]> generator = Staff[]::new;
          Staff[] array = tmpList.stream().toArray(generator);
          System.out.println(Arrays.deepToString(array));
      }
      

提示 Stream上半部分已學習完畢,Stream下半部分的學習可見《【jdk1.8特性】之Stream(下)》


^_^ 如有不當之處,歡迎指正

^_^ 參考資料
        《jdk api 1.8_google.CHM》

^_^ 參考鏈接
        https://blog.csdn.net…ails/88640557
        https://www.jianshu.com/p/19ffb2c9438a

^_^ 測試代碼託管鏈接
        https://github.com/JustryDeng…Jdk8Feature

^_^ 本文已經被收錄進《程序員成長筆記(五)》,筆者JustryDeng

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章