Java8實戰之Stream流式操作

簡介

Java8中有兩大最爲重要的改變。第一個是Lambda 表達式;另外一個則是Stream API(java.util.stream.*)
StreamJava8 中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執行非常複雜的查找、過濾和映射數據等操作。使用Stream API 對集合數據進行操作,就類似於使用SQL 執行的數據庫查詢。也可以使用Stream API來並行執行操作。簡而言之,Stream API提供了一種高效且易於使用的處理數據的方式。

Stream(流)是數據渠道,用於操作數據源(集合、數組等)所生成的元素序列。“集合講的是數據,流講的是計算!”

注意:
1.Stream 自己不會存儲元素。
2. Stream 不會改變源對象。相反,他們會返回一個持有結果的新Stream。
3. Stream操作是延遲執行的。這意味着他們會等到需要結果的時候才執行

Stream操作步驟

  1. 創建Stream:一個數據源(如:集合、數組),獲取一個流
  2. 中間操作:一箇中間操作鏈,對數據源的數據進行處理
  3. 終止操作(終端操作):一個終止操作,執行中間操作鏈,併產生結果

流程如下圖所示:
在這裏插入圖片描述

創建Stream

方式一:Java8 中的Collection 接口被擴展,提供了兩個獲取流的方法:

  • default Stream<E> stream(): 返回一個順序流
  • default Stream<E> parallelStream() : 返回一個並行流
// 1、 通過Collection集合提供的stream()或parallelStream()
List<String> list = new ArrayList<>();
// stream()
Stream<String> stream1 = list.stream();
// parallelStream()
Stream<String> parallelStream = list.parallelStream();

方式二:通過Arrays中的靜態方法stream()獲取數組流

// 2、通過Arrays中的靜態方法stream()獲取數組流
String[] strArray = {"1","2"};
Stream<String> stream2 = Arrays.stream(strArray);

方式三:通過stream類中的靜態方法of(),它可以接收任意數量的參數

// 通過stream類中的靜態方法of()
Stream<String> stream3 = Stream.of("1", "2");

方式四:創建無限流,可以使用靜態方法Stream.iterate()Stream.generate(), 創建無限流

// 4、創建無限流
// 使用迭代
Stream<Integer> iterateStream = Stream.iterate(0, (e) -> e + 2);
iterateStream.limit(10).forEach(System.out::println);

// 使用生成
Stream<Double> generateStream = Stream.generate(() -> Math.random());
generateStream.limit(10).forEach(System.out::println);

Stream的中間操作

多箇中間操作可以連接起來形成一個流水線,除非流水線上觸發終止操作,否則中間操作不會執行任何的處理!而在終止操作時一次性全部處理,稱爲“惰性求值

篩選與切片:

 /**
  * 切片與篩選
  *
  * filter(Predicatep):接收Lambda ,從流中排除某些元素。
  * limit(long maxSize):截斷流,使其元素不超過給定數量。
  * skip(long n):跳過元素,返回一個扔掉了前n 個元素的流。若流中
  * distinct():篩選,通過流所生成元素的hashCode() 和equals() 去除重複元素
  */
 @Test
 public void test2(){
     // 中間操作:不會執行任何操作
     Stream<User> userStream = userList.stream().filter((e) -> {
         System.out.println("stream 中間操作");
         return e.getAge() > 20;
     });

     // 終止操作:一次性執行完全部內容,稱爲"惰性求值"
     userStream.forEach(System.out::println);
 }

 // limit(long maxSize):截斷流,使其元素不超過給定數量
 @Test
 public void test3(){
     userList.stream().limit(2).forEach(System.out::println);
 }


 // skip(long n):跳過元素,返回一個扔掉了前n 個元素的流。若流中
 @Test
 public void test4(){
     userList.stream().skip(2).forEach(System.out::println);

 }

 // distinct():篩選,通過流所生成元素的hashCode() 和equals() 去除重複元素
 @Test
 public void test5(){
     userList.stream().distinct().forEach(System.out::println);
 }

映射:

/**
  * 映射
  *
  *
  * map(Functionf):接收一個函數作爲參數,該函數會被應用到每個元素上,並將其映射成一個新的元素。
  * flatMap(Function f):接收一個函數作爲參數,將流中的每個值都換成另一個流,然後把所有流連接成一個流
  */
 // map(Functionf):接收一個函數作爲參數,該函數會被應用到每個元素上,並將其映射成一個新的元素。
 @Test
 public void test6(){
     userList.stream().map(User::getName).forEach(System.out::println);
 }

 // flatMap(Function f):接收一個函數作爲參數,將流中的每個值都換成另一個流,然後把所有流連接成一個流
 @Test
 public void test7() {
     List<String> list = Arrays.asList("a a", "c c", "d d", "b b");
     Stream<String> stringStream = list.stream().flatMap(e -> Arrays.stream(e.split(" ")));
     stringStream.forEach(System.out::println);
 }

排序:

/**
  * 排序
  *
  * sorted():產生一個新流,其中按自然順序排序
  * sorted(Comparatorcomp):產生一個新流,其中按比較器順序排序
  */

 // sorted():產生一個新流,其中按自然順序排序
 @Test
 public void test8(){
     List<String> list = Arrays.asList("a a", "c c", "d d", "b b");
     list.stream().sorted().forEach(System.out::println);
 }

 // sorted(Comparatorcomp):產生一個新流,其中按比較器順序排序
 @Test
 public void test9(){
    userList.stream().sorted((e1,e2) -> {
        if(e1.getAge() > e2.getAge()){
             return 1;
        }
        return 0;
    }).forEach(System.out::println);
 }

Stream的終止操作

查找與匹配:

/**
  * 查找與匹配
  *
  * allMatch(Predicate p):檢查是否匹配所有元素
  * anyMatch(Predicate p): 檢查是否至少匹配一個元素
  * noneMatch(Predicatep):檢查是否沒有匹配所有元素
  * findFirst():返回第一個元素
  * findAny():返回當前流中的任意元素
  * count():返回流中元素總數
  * max(Comparatorc):返回流中最大值
  * min(Comparatorc):返回流中最小值
  * forEach(Consumerc):內部迭代(使用Collection 接口需要用戶去做迭代,稱爲外部迭代。相反,Stream API 使用內部迭代——它幫你把迭代做了)
  */
 // allMatch(Predicate p):檢查是否匹配所有元素
 @Test
 public void test10() {
     boolean b = userList.stream().allMatch((e) -> "男".equals(e.getGender()));
     System.out.println("allMatch:" + b);
 }

 // anyMatch(Predicate p): 檢查是否至少匹配一個元素
 @Test
 public void test11(){
     boolean b = userList.stream().anyMatch((e) -> "男".equals(e.getGender()));
     System.out.println("anyMatch:" + b);
 }

 // noneMatch(Predicatep):檢查是否沒有匹配所有元素
 @Test
 public void test12(){
     boolean b = userList.stream().noneMatch((e) -> "男".equals(e.getGender()));
     System.out.println("noneMatch:" + b);
 }

 // findFirst():返回第一個元素
 @Test
 public void test13(){
     Optional<User> first = userList.stream().findFirst();
     System.out.println(first.get());
 }

 // findAny():返回當前流中的任意元素
 @Test
 public void test14(){
     Optional<User> any = userList.stream().findAny();
     System.out.println(any.get());
 }

 // count():返回流中元素總數
 @Test
 public void test15(){
     long count = userList.stream().count();
     System.out.println(count);
 }

 // max(Comparatorc):返回流中最大值
 @Test
 public void test16(){
     Optional<User> max = userList.stream().max((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge()));
     System.out.println(max.get());
 }

 // min(Comparatorc):返回流中最小值
 @Test
 public void test17(){
     Optional<User> max = userList.stream().min((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge()));
     System.out.println(max.get());
 }

 // forEach(Consumerc):內部迭代(使用Collection 接口需要用戶去做迭代,稱爲外部迭代。相反,Stream API 使用內部迭代——它幫你把迭代做了)
 @Test
 public void test18(){
     userList.stream().forEach(System.out::println);
 }

規約:

/**
  * 規約
  *
  * reduce(T iden, BinaryOperator b):可以將流中元素反覆結合起來,得到一個值。返回T
  * reduce(BinaryOperator b):可以將流中元素反覆結合起來,得到一個值。返回Optional<T>
  */
 // reduce(T iden, BinaryOperator b):可以將流中元素反覆結合起來,得到一個值。返回T
 @Test
 public void test19() {
     List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
     Integer reduce = list.stream().reduce(0, (x, y) -> x + y);
     System.out.println(reduce);
 }

 // reduce(BinaryOperator b):可以將流中元素反覆結合起來,得到一個值。返回Optional<T>
 @Test
 public void test20(){
     Optional<Integer> reduce = userList.stream().map(User::getAge).reduce(Integer::sum);
     System.out.println(reduce.get());
 }

收集:

/**
  * 收集
  *
  * collect(Collector c):將流轉換爲其他形式。接收一個Collector接口的實現,用於給Stream中元素做彙總的方法
  *
  */
 @Test
 public void test21() {
     // toList
     List<User> list = userList.stream().collect(Collectors.toList());
     list.forEach(System.out::println);

     System.out.println("-----------------------");

     // toSet
     Set<User> userSet = userList.stream().collect(Collectors.toSet());
     userSet.forEach(System.out::println);

     System.out.println("-----------------------");

     // 計算流中元素的個數
     Long count = userList.stream().collect(Collectors.counting());
     System.out.println(count);

     System.out.println("-----------------------");

     // 平均值
     Double avg = userList.stream().collect(Collectors.averagingDouble(User::getAge));
     System.out.println(avg);

     System.out.println("-----------------------");

     // 總和
     Double sum = userList.stream().collect(Collectors.summingDouble(User::getAge));
     System.out.println(sum);

     System.out.println("-----------------------");

     // 最大值
     Optional<User> max = userList.stream().collect(Collectors.maxBy((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())));
     System.out.println(max.get());

     System.out.println("-----------------------");

     // 最小值
     Optional<Integer> min = userList.stream().map(User::getAge).collect(Collectors.minBy(Integer::compare));
     System.out.println(min);

     System.out.println("-----------------------");

     // 分組
     Map<String, List<User>> group = userList.stream().collect(Collectors.groupingBy(User::getGender));
     System.out.println(group);

     System.out.println("-----------------------");

     // 多級分組
     Map<String, Map<Integer, List<User>>> multilevelGroup = userList.stream().collect(Collectors.groupingBy(User::getGender, Collectors.groupingBy(User::getAge)));
     System.out.println(multilevelGroup);

     System.out.println("-----------------------");

     // 根據true或false進行分區
     Map<Boolean, List<User>> area = userList.stream().collect(Collectors.partitioningBy((e) -> e.getGender().equals("男")));
     System.out.println(area);

     System.out.println("-----------------------");

     // 求統計值
     DoubleSummaryStatistics summaryStatistics = userList.stream().collect(Collectors.summarizingDouble(User::getAge));
     System.out.println(summaryStatistics.getMax());
     System.out.println(summaryStatistics.getMin());
     System.out.println(summaryStatistics.getCount());
     System.out.println(summaryStatistics.getAverage());

     System.out.println("-----------------------");

     // 連接字符串
     String joining = userList.stream().map(User::getName).collect(Collectors.joining());
     System.out.println(joining);

     System.out.println("-----------------------");

     // 連接字符串,按符號分隔
     String joiningSp = userList.stream().map(User::getName).collect(Collectors.joining(","));
     System.out.println(joiningSp);

     // 從一個作爲累加器的初始值開始,利用BinaryOperator與流中元素逐個結合,從而歸約成單個值
     Integer reducing = userList.stream().collect(Collectors.reducing(0, User::getAge, Integer::sum));
     System.out.println(reducing);

     // 包裹另一個收集器,對其結果轉換函數
     Integer collectingAndThen = userList.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
     System.out.println(collectingAndThen);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章