【重學Java】Stream流

gonghr發表於2021-07-13

Stream流

體驗Stream流【理解】

  • 案例需求

    按照下面的要求完成集合的建立和遍歷

    • 建立一個集合,儲存多個字串元素
    • 把集合中所有以"張"開頭的元素儲存到一個新的集合
    • 把"張"開頭的集合中的長度為3的元素儲存到一個新的集合
    • 遍歷上一步得到的集合
  • 原始方式示例程式碼

    public class StreamDemo {
        public static void main(String[] args) {
            //建立一個集合,儲存多個字串元素
            ArrayList<String> list = new ArrayList<String>();
    
            list.add("林青霞");
            list.add("張曼玉");
            list.add("王祖賢");
            list.add("柳巖");
            list.add("張敏");
            list.add("張無忌");
    
            //把集合中所有以"張"開頭的元素儲存到一個新的集合
            ArrayList<String> zhangList = new ArrayList<String>();
    
            for(String s : list) {
                if(s.startsWith("張")) {
                    zhangList.add(s);
                }
            }
    
    //        System.out.println(zhangList);
    
            //把"張"開頭的集合中的長度為3的元素儲存到一個新的集合
            ArrayList<String> threeList = new ArrayList<String>();
    
            for(String s : zhangList) {
                if(s.length() == 3) {
                    threeList.add(s);
                }
            }
    
    //        System.out.println(threeList);
    
            //遍歷上一步得到的集合
            for(String s : threeList) {
                System.out.println(s);
            }
            System.out.println("--------");
    
            //Stream流來改進
            list.stream().filter(s -> s.startsWith("張")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));
    
        }
    }
    
  • Stream流的好處

    • 直接閱讀程式碼的字面意思即可完美展示無關邏輯方式的語義:獲取流、過濾姓張、過濾長度為3、逐一列印
    • Stream流把真正的函數語言程式設計風格引入到Java中
    • 程式碼簡潔

Stream流的常見生成方式【應用】

  • Stream流的思想

image

  • Stream流的三類方法

    • 獲取Stream流
      • 建立一條流水線,並把資料放到流水線上準備進行操作
    • 中間方法
      • 流水線上的操作
      • 一次操作完畢之後,還可以繼續進行其他操作
    • 終結方法
      • 一個Stream流只能有一個終結方法
      • 是流水線上的最後一個操作
  • 生成Stream流的方式

    • Collection體系集合(單列集合)

      使用預設方法stream()生成流, default Stream stream()

    • Map體系集合(雙列集合)

      把Map轉成Set集合,間接的生成流

    • 陣列

      通過Arrays中的靜態方法stream生成流

    • 同種資料型別的多個資料

      通過Stream介面的靜態方法of(T... values)生成流

  • 程式碼演示

    public class StreamDemo {
        public static void main(String[] args) {
            //Collection體系的集合可以使用預設方法stream()生成流
            List<String> list = new ArrayList<String>();
            Stream<String> listStream = list.stream();
    
            Set<String> set = new HashSet<String>();
            Stream<String> setStream = set.stream();
    
            //Map體系的集合間接的生成流
            Map<String,Integer> map = new HashMap<String, Integer>();
            Stream<String> keyStream = map.keySet().stream();
            Stream<Integer> valueStream = map.values().stream();
            Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
    
            //陣列可以通過Arrays中的靜態方法stream生成流
            String[] strArray = {"hello","world","java"};
            Stream<String> strArrayStream = Arrays.stream(strArray);
          
          	//同種資料型別的多個資料可以通過Stream介面的靜態方法of(T... values)生成流
            Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");
            Stream<Integer> intStream = Stream.of(10, 20, 30);
        }
    }
    

Stream流中間操作方法【應用】

  • 概念

    中間操作的意思是,執行完此方法之後,Stream流依然可以繼續執行其他操作

  • 常見方法

    方法名 說明
    Stream filter(Predicate predicate) 用於對流中的資料進行過濾
    Stream limit(long maxSize) 返回此流中的元素組成的流,擷取前指定引數個數的資料
    Stream skip(long n) 跳過指定引數個數的資料,返回由該流的剩餘元素組成的流
    static Stream concat(Stream a, Stream b) 合併a和b兩個流為一個流
    Stream distinct() 返回由該流的不同元素(根據Object.equals(Object) )組成的流(自定義資料型別重寫equals和hashCode
  • filter原理

          ArrayList list = new ArrayList(List.of(1,2,3,4));
          list.stream().filter(new Predicate() {
              @Override
              public boolean test(Object o) {
                  return false;
              }
          });
        //Predicate中有一個抽象方法test可以使用匿名內部類或者lambda表示式
        //filter方法獲取流中的每一個資料
        //而test中的s,依次表示流中的每一個資料
        //我們只需要在流中對s進行判斷就行了
        //如果判斷結果為true,則當前結果留下
        //如果判斷結果為false,則當前結果不要
    
  • filter程式碼演示

    public class StreamDemo01 {
        public static void main(String[] args) {
            //建立一個集合,儲存多個字串元素
            ArrayList<String> list = new ArrayList<String>();
    
            list.add("林青霞");
            list.add("張曼玉");
            list.add("王祖賢");
            list.add("柳巖");
            list.add("張敏");
            list.add("張無忌");
    
            //需求1:把list集合中以張開頭的元素在控制檯輸出
            list.stream().filter(s -> s.startsWith("張")).forEach(System.out::println);
            System.out.println("--------");
    
            //需求2:把list集合中長度為3的元素在控制檯輸出
            list.stream().filter(s -> s.length() == 3).forEach(System.out::println);
            System.out.println("--------");
    
            //需求3:把list集合中以張開頭的,長度為3的元素在控制檯輸出
            list.stream().filter(s -> s.startsWith("張")).filter(s -> s.length() == 3).forEach(System.out::println);
        }
    }
    
  • limit&skip程式碼演示

    public class StreamDemo02 {
        public static void main(String[] args) {
            //建立一個集合,儲存多個字串元素
            ArrayList<String> list = new ArrayList<String>();
    
            list.add("林青霞");
            list.add("張曼玉");
            list.add("王祖賢");
            list.add("柳巖");
            list.add("張敏");
            list.add("張無忌");
    
            //需求1:取前3個資料在控制檯輸出
            list.stream().limit(3).forEach(System.out::println);
            System.out.println("--------");
    
            //需求2:跳過3個元素,把剩下的元素在控制檯輸出
            list.stream().skip(3).forEach(System.out::println);
            System.out.println("--------");
    
            //需求3:跳過2個元素,把剩下的元素中前2個在控制檯輸出
            list.stream().skip(2).limit(2).forEach(System.out::println);
        }
    }
    
  • concat&distinct程式碼演示

    public class StreamDemo03 {
        public static void main(String[] args) {
            //建立一個集合,儲存多個字串元素
            ArrayList<String> list = new ArrayList<String>();
    
            list.add("林青霞");
            list.add("張曼玉");
            list.add("王祖賢");
            list.add("柳巖");
            list.add("張敏");
            list.add("張無忌");
    
            //需求1:取前4個資料組成一個流
            Stream<String> s1 = list.stream().limit(4);
    
            //需求2:跳過2個資料組成一個流
            Stream<String> s2 = list.stream().skip(2);
    
            //需求3:合併需求1和需求2得到的流,並把結果在控制檯輸出
    //        Stream.concat(s1,s2).forEach(System.out::println);
    
            //需求4:合併需求1和需求2得到的流,並把結果在控制檯輸出,要求字串元素不能重複
            Stream.concat(s1,s2).distinct().forEach(System.out::println);
        }
    }
    

Stream流終結操作方法【應用】

  • 概念

    終結操作的意思是,執行完此方法之後,Stream流將不能再執行其他操作

  • 常見方法

    方法名 說明
    void forEach(Consumer action) 獲取流的每個元素並對其執行操作
    long count() 返回此流中的元素數
  • 程式碼演示

    public class StreamDemo {
        public static void main(String[] args) {
            //建立一個集合,儲存多個字串元素
            ArrayList<String> list = new ArrayList<String>();
    
            list.add("林青霞");
            list.add("張曼玉");
            list.add("王祖賢");
            list.add("柳巖");
            list.add("張敏");
            list.add("張無忌");
    
            //需求1:把集合中的元素在控制檯輸出
    	//list.stream().forEach(System.out::println);
      
    	//list.stream().forEach(new Consumer() {
      //          @Override
      //          public void accept(Object o) {
      //            
      //          }
      //      });
      //在forEach方法底層會迴圈呼叫流中每一個資料
      //並迴圈呼叫accept方法,把每一個資料傳遞給accept方法
      //s就依次代表流中的每一個資料
      //所以只需要在accept方法中編寫相應的業務邏輯即可
      
            //需求2:統計集合中有幾個以張開頭的元素,並把統計結果在控制檯輸出
            long count = list.stream().filter(s -> s.startsWith("張")).count();
            System.out.println(count);
        }
    }
    

Stream流的收集操作【應用】

  • 概念

    對資料使用Stream流的方式操作完畢後,可以把流中的資料收集到集合中

  • 常用方法

    方法名 說明
    R collect(Collector collector) 把結果收集到集合中
  • 工具類Collectors提供了具體的收集方式

    方法名 說明
    public static Collector toList() 把元素收集到List集合中
    public static Collector toSet() 把元素收集到Set集合中
    public static Collector toMap(Function keyMapper,Function valueMapper) 把元素收集到Map集合中
  • 程式碼演示

    • 單列集合
    ArrayList<Integer> list = new ArrayList<Integer>(List.of(1, 2, 3, 4,4,4));
    
          //filter負責過濾資料
          //collect負責收集資料
          //獲取流中剩餘的資料,但是他不負責建立容器,也不負責把資料新增到容器中
          //Collectors.toList()會在底層建立一個List集合,並把所以的資料新增到List集合中。
      	
          List<Integer> list1 = list.stream().filter(number -> number % 2 == 0).collect(Collectors.toList());
          System.out.println(list1);
    
          Set<Integer> set = list.stream().filter(number -> number % 2 == 0).collect(Collectors.toSet());
          System.out.println(set);
      //[2, 4, 4, 4]
      //[2, 4]
    
    • 雙列集合
    public static void main(String[] args) {
          /**
           * Steam流的收集方法
           *
           * 建立一個ArrayList集合,並新增以下的字串,字串中前面是姓名,後面是年齡
           * "zhangsan,23"
           * "lisi,24"
           * "wangwu,25"
           * 保留年齡大於等於24歲的人,並將結果收集到Map集合中,姓名為鍵,年齡為值
           */
          ArrayList<String> list = new ArrayList<>(List.of("zhangsan,23","lisi,24","wangwu,25"));
          Map<String,Integer> map = list.stream().filter((String s)->{
              String[] split = s.split(",");
              int i = Integer.parseInt(split[1]);
              return i>=24;
          }).collect(Collectors.toMap(
                  (String s)-> {
                      return s.split(",")[0];
                  },
                  (String s)->{
                      return Integer.valueOf(s.split(",")[1]);
                  }
          ));
          map.forEach((String s,Integer i)->{
              System.out.println(s+"---"+i);
          });
      }
    

Stream流綜合練習【應用】

  • 案例需求

image

  • 程式碼實現

    演員類

    public class Actor {
        private String name;
    
        public Actor(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

    測試類

    package com.cnblogs.gonghr;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;
    
    public class test13 {
      public static void main(String[] args) {
          String actor_man_one = "周潤發";
          String actor_man_two = "成龍";
          String actor_man_three = "劉德華";
          String actor_man_four = "吳京";
          String actor_man_five = "周星馳";
          String actor_man_six = "李連杰";
          ArrayList<String> actors_man = new ArrayList<>(List.of(actor_man_one, actor_man_two, actor_man_three, actor_man_four, actor_man_five, actor_man_six));
          String actor_woman_one = "林心如";
          String actor_woman_two = "張曼玉";
          String actor_woman_three = "楊超越";
          String actor_woman_four = "林志玲";
          String actor_woman_five = "周冬雨";
          String actor_woman_six = "楊穎";
          ArrayList<String> actors_woman = new ArrayList<>(List.of(actor_woman_one, actor_woman_two, actor_woman_three, actor_woman_four, actor_woman_five, actor_woman_six));
          Stream<String> actorStream_man= actors_man.stream().filter(actor -> actor.length() == 3).limit(2);
          Stream<String> actorStream_woman = actors_woman.stream().filter(actor -> actor.startsWith("楊")).skip(1);
          Stream.concat(actorStream_man, actorStream_woman).forEach(s->{
              Actor actor = new Actor(s);
              System.out.println(actor);
          });
      }
    }
    //Actor{name='周潤發'}
    //Actor{name='劉德華'}
    //Actor{name='楊穎'}
    

相關文章