­

【重学Java】Stream流

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='杨颖'}
    
Tags: