• 11-stream流-流水线编码、filter等中间方法、forEach等终止方法、collect获取返回结果方法、lambda练习


    1、体验Stream流【理解】

    • 案例需求

      按照下面的要求完成集合的创建和遍历

      • 创建一个集合,存储多个字符串元素
      • 把集合中所有以"云"开头的元素存储到一个新的集合
      • 再把"云"开头的集合中的长度为3的元素存储到一个新的集合
      • 遍历上一步得到的集合
    • 原始方式示例代码

        public static void main(String[] args) {
            ArrayList<String> list1=new ArrayList<>();
            initList(list1);
            System.out.println(list1);
    
            ArrayList<String> list2=new ArrayList<>();
            for (String s : list1) {
                if(s.startsWith("云")) list2.add(s);
            }
            System.out.println(list2);
    
            ArrayList<String> list3=new ArrayList<>();
            for (String s : list2) {
                if(s.length()==3) list3.add(s);
            }
            System.out.println(list3);
        }
    
        public static void initList(ArrayList<String> list){
            String[] ss={"云天河","韩菱纱","慕容紫英","柳梦璃","玄霄","夙玉","云天青","云来石","云叔"};
            for (String s : ss) list.add(s);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    • 使用Stream流示例代码(三行就实现了复杂逻辑)
        public static void main(String[] args) {
            ArrayList<String> list1=new ArrayList<>();
            initList(list1);
            System.out.println(list1);
    
            //stream流,借助lambda表达式,非常简单
            list1.stream().filter(s -> s.startsWith("云"))
                    .filter(s -> s.length()==3)
                    .forEach(s -> System.out.print(s+" "));
    
        }
    
        public static void initList(ArrayList<String> list){
            String[] ss={"云天河","韩菱纱","慕容紫英","柳梦璃","玄霄","夙玉","云天青","云来石","云叔"};
            for (String s : ss) list.add(s);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    • Stream流的好处

      • 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为
    • 逐一打印

      • Stream流把真正的函数式编程风格引入到Java中
      • 代码简洁

    2、Stream流的常见生成方式【应用】

    • Stream流的思想

    在这里插入图片描述

    • Stream流的三类方法

      • 获取Stream流
        • 创建一条流水线,并把数据放到流水线上准备进行操作
      • 中间方法
        • 流水线上的操作
        • 一次操作完毕之后,还可以继续进行其他操作
      • 终结方法
        • 一个Stream流只能有一个终结方法
        • 是流水线上的最后一个操作
    • 生成Stream流的方式

      • Collection体系集合

        使用默认方法stream()生成流, default Stream< E> stream()

      • Map体系集合

        把Map转成Set集合(keySet或entrySet),间接的生成流

      • 数组

        通过Arrays中的静态方法stream生成流

      • 同种数据类型的多个数据

        通过Stream接口的静态方法of(T… values)生成流

    • 代码演示

    代码1:单列集合流

    获取stream流: Stream< String> stream = list.stream();
    操作stream流: stream.forEach(s -> System.out.print(s+" "));

        public static void main(String[] args) {
            //单列集合
            ArrayList<String> list = new ArrayList<>();
            initList(list);
            System.out.println(list);
    
            //单列集合生成流
            Stream<String> stream = list.stream();
            //查看流里有啥
            stream.forEach(s -> System.out.print(s+" "));//”aaa bbb ccc “
            System.out.println();
            //一般流都是直接写再一起的
            list.stream().forEach(s -> System.out.print(s+" "));//”aaa bbb ccc “
    
        }
    
        public static void initList(ArrayList<String> list){
            String[] ss={"aaa","bbb","ccc"};
            for (String s : ss) list.add(s);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    代码2:双列集合流

    先获取keySet或者entrySet,再获取流
    map.keySet().stream() 或者 map.entrySet().stream()

        public static void main(String[] args) {
            //双列集合
            HashMap<String,Integer> hm=new HashMap<>();
            initList(hm);
            //System.out.println(hm);
    
            //开始先获取stream流
            //注意:双列集合不能直接获取stream流
            //1.keySet
                //1.1先获取keySet(所有的键)
                //1.2再把这个Set集合中所有的键放到Stream流中
            hm.keySet().stream().forEach(s -> System.out.print(s+" "));
            //上行输出:lisi zhaoliu zhangsan wangwu tianqi
    
            System.out.println("\n===========================================");
            //2.entrySet
                //2.1先获取所有的键值对对象(entrySet)
                //2.2再把这个Set集合中所有键值对对象放到Stream流中
            hm.entrySet().stream().forEach(s ->System.out.println(s));
    
    
        }
    
        public static void initList(HashMap<String,Integer> map){
            String[] name={"zhangsan","lisi","wangwu","zhaoliu","tianqi"};
            Integer[] age={23,24,25,26,27};
            for(int i=0;i<name.length;i++) map.put(name[i],age[i]);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述

    代码3:数组—》流

        public static void main(String[] args) {
            //数组-》流
            int[] arr={1,2,3,4,5};
            Arrays.stream(arr).forEach(s->System.out.print(s+" "));//"1 2 3 4 5"
            
            //拓展
            System.out.println();
            System.out.println(Arrays.toString(arr));//数组输出
            System.out.println(Arrays.stream(arr).max().getAsInt());//流求 数组最大值 5
            System.out.println(Arrays.stream(arr).min().getAsInt());//流求 数组最小值 1
            System.out.println(Arrays.stream(arr).average().getAsDouble());//流求 数组平均 3.0
            System.out.println(Arrays.stream(arr).count());//流求 数组长度 5
            System.out.println(Arrays.stream(arr).sum());//流求 数组求和 15
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    代码4:同种数据类型的多个数据

        public static void main(String[] args) {
            //同种数据类型多个数据->流水线
            Stream.of(1,4,6,7,8,2,3,5,10,9).forEach(s->System.out.print(s+" "));
    
            System.out.println();
            //DIY应用 过滤掉奇数
            Stream.of(1,4,6,7,8,2,3,5,10,9).filter(i->i%2!=0)
                    .forEach(i->System.out.print(i+" "));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    Stream流的获取小结

     单列集合 : 集合对象.stream();
     双列集合 : 不能直接获取,需要间接获取
                集合对象.keySet().stream();
                集合对象.entrySet().stream();
     数组     :
                Arrays.stream(数组名);
     同种数据类型的多个数据:
                Stream.of(数据1,数据2,数据3......);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3、Stream流中间操作方法【应用】

    • 概念

      中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作

    • 常见方法

      方法名说明
      Stream< T> filter(Predicate predicate)用于对流中的数据进行过滤
      Stream< T> limit(long maxSize)返回此流中的元素组成的流,截取指定参数个数的数据
      Stream< T> skip(long n)跳过指定参数个数的数据,返回由该流的剩余元素组成的流
      static < T> Stream< T> concat(Stream a, Stream b)合并a和b两个流为一个流
      Stream< T> distinct()返回由该流的不同元素(根据hashCode和equals方法 )组成的流

    filter代码演示

        public static void main(String[] args) {
            ArrayList<String> list1=new ArrayList<>();
            initList(list1);
            System.out.println(list1);
    
            //留下"云"开头的  过滤掉其他的
            //filter方法获取流中的每个数据
            //而test方法中的s,就依次表示流中的每一个数据
            //则只需在test方法中s进行判断就行了:true该数据留校   false该数据丢弃
            System.out.println("==============匿名内部类=============");
            list1.stream().filter(new Predicate<String>() {
                @Override
                public boolean test(String s) {
                    return s.startsWith("云");
                }
            }).forEach(s->System.out.print(s+" "));
    
            System.out.println("\n==============lambda表达式=============");
            //因为Predicate接口中只有一个★抽象方法Test★,因此可以用lambda表达式简化
            //接下来,再用lambda表达式简化一下就ok了
            list1.stream().filter((String s)->{
                return s.startsWith("云");
            }).forEach(s->System.out.print(s+" "));
    
            System.out.println("\n==============lambda表达式省略写法=============");
            //参数只有一个: 可以省略 类型与括号()
            //方法体语句只有一条: return可以省略 ";"可以省略
            list1.stream().filter(s->s.startsWith("云")).forEach(s->System.out.print(s+" "));
        }
    
        public static void initList(ArrayList<String> list){
            String[] ss={"云天河","韩菱纱","慕容紫英","柳梦璃","玄霄","夙玉","云天青","云来石","云叔"};
            for (String s : ss) list.add(s);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在这里插入图片描述

    limit&skip代码演示

    Stream< T> limit(long maxSize); || eg:limit(3) 截取前3个数据 Stream< T>
    Stream< T> skip(long n) || eg:skip(3) 前3个数据不要(剩余的都留下)

        public static void main(String[] args) {
            ArrayList<String> list1=new ArrayList<>();
            initList(list1);
            System.out.println(list1);
    
            //Stream< T> limit(long maxSize);  eg:limit(3) 截取前3个数据
            System.out.println("==============.stream().limit(2)================");
            list1.stream().limit(2).forEach(s -> System.out.print(s+" "));//云天河 韩菱纱
            
            //Stream< T> skip(long n)  eg:skip(3) 前3个数据不要(剩余的都留下)
            System.out.println("\n==============.stream().skip(2)================");
            list1.stream().skip(2).forEach(s -> System.out.print(s+" "));
        }
    
        public static void initList(ArrayList<String> list){
            String[] ss={"云天河","韩菱纱","慕容紫英","柳梦璃","玄霄","夙玉","云天青","云来石","云叔"};
            for (String s : ss) list.add(s);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    concat&distinct代码演示

    static < T> Stream< T> concat(Stream a, Stream b) | 合并a和b两个流为一个流
    Stream< T> distinct() 流中数据去重(根据hashCode和equals方法 )

        public static void main(String[] args) {
            ArrayList<String> list1=new ArrayList<>();
            ArrayList<String> list2=new ArrayList<>();
            initList(list1);initList(list2);
            System.out.println(list1);
            System.out.println(list2);
             
            //static < T> Stream< T> concat(Stream a, Stream b) | 合并a和b两个流为一个流
            System.out.println("==================合并====================");
            Stream<String> stream = Stream.concat(list1.stream(), list2.stream());
            stream.forEach(s -> System.out.print(s+" "));
            //【stream被终止方法操作过一次就会终止,不能再被操作了】
    
    
            //Stream< T> distinct()    流中数据去重(根据hashCode和equals方法 )
            System.out.println("\n==================去重====================");
            //上面的stream流水线已经结束了  不能再使用了  (应该forEach是终止方法)
            Stream<String> stream2 = Stream.concat(list1.stream(), list2.stream());
            stream2.distinct().forEach(s -> System.out.print(s+" "));
    
        }
    
        public static void initList(ArrayList<String> list){
            String[] ss={"云天河","韩菱纱","慕容紫英","柳梦璃","玄霄","夙玉","云天青","云来石","云叔"};
            for (String s : ss) list.add(s);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    4、Stream流终结操作方法【应用】

    • 概念(★)

      终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作

    • 常见方法

      方法名说明
      void forEach(Consumer action)对此流的每个元素执行操作
      long count()返回此流中的元素数

    forEach

        public static void main(String[] args) {
            ArrayList<String> list1=new ArrayList<>();
            initList(list1);
            System.out.println(list1);
    
            //终结方法1:forEach 【终结方法执行后,本次流水线结束。不能再操作此流水线了】
            System.out.println("=============forEach:匿名内部类============");
            //在forEach方法的底层,会循环获取到流中的每一个数据.
            //并循环调用accept方法,并把每一个数据传递给accept方法
            //s就依次表示了流中的每一个数据.
            //所以,我们只要在accept方法中,写上处理的业务逻辑就可以了.
            list1.stream().forEach(new Consumer<String>() {
                @Override
                public void accept(String s) {
                    System.out.print(s+" ");
                }
            });
    
            //Consumer接口内只有一个抽象方法,可以用lambda表达式
            System.out.println("\n=============forEach:lambda表达式============");
            list1.stream().forEach((String s)->{
                System.out.print(s+" ");
            });
    
            //一个参数:省略 类型+小括号
            //一条语句:省略 return、分号、大括号
            System.out.println("\n=============forEach:lambda表达式简化============");
            list1.stream().forEach(s->System.out.print(s+" "));
        }
    
        public static void initList(ArrayList<String> list){
            String[] ss={"云天河","韩菱纱","慕容紫英","柳梦璃","玄霄","夙玉","云天青","云来石","云叔"};
            for (String s : ss) list.add(s);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在这里插入图片描述

    count() 返回此流中的元素数

        public static void main(String[] args) {
            ArrayList<String> list1=new ArrayList<>();
            initList(list1);
            System.out.println(list1);
    
            //终结方法2:count(): 统计流中元素个数【终结方法执行后,本次流水线结束。不能再操作此流水线了】
            long count = list1.stream().count();
            System.out.println(count);//9
        }
    
        public static void initList(ArrayList<String> list){
            String[] ss={"云天河","韩菱纱","慕容紫英","柳梦璃","玄霄","夙玉","云天青","云来石","云叔"};
            for (String s : ss) list.add(s);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    在Stream流中无法直接修改集合、数组等数据源中的数据(无法直接修改那块内存)

    Stream流的收集方法
    练习:
    定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10
    将集合中的奇数删除,只保留偶数。
    遍历集合得到2,4,6,8,10。

        public static void main(String[] args) {
            ArrayList<Integer> list=new ArrayList<>();
            for (int i = 1; i < 10; i++)  list.add(i);//快捷写法:  10.fori
    
            System.out.println("=============用流去重后输出流=============");
            list.stream().filter(i -> i%2==0).forEach(i->System.out.print(i+" "));
    
            System.out.println("\n=============输出原集合=============");
            System.out.println(list);//list完好无损: 说明list.stream().filter并没有直接修改list集合的数据  
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    5、Stream流的收集操作【应用】

    stream流无法直接修改集合中元素,有修改需求时咋办呢?有专门的收集API

    • 概念

      对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中

    • 常用方法(collect也是终结方法)

      方法名说明
      R collect(Collector collector)把结果收集到集合中
    • 工具类Collectors提供了具体的收集方式

      方法名说明
      public static Collector toList()把元素收集到List集合中
      public static Collector toSet()把元素收集到Set集合中
      public static Collector toMap(Function keyMapper,Function valueMapper)把元素收集到Map集合中

    收集到List和Set 单列集合中

    案例: 只保留list集合中的偶数(删除所有奇数)

        public static void main(String[] args) {
            ArrayList<Integer> list1=new ArrayList<>();
            for (int i = 1; i <= 10; i++)  list1.add(i);//快捷写法:  10.fori
            list1.add(10);list1.add(10);list1.add(10);list1.add(10);list1.add(10);
            
            //1.收集到list中
            //filter负责过滤数据的.
            //collect负责收集数据.
                //获取流中剩余的数据,但是他不负责创建容器,也不负责把数据添加到容器中.
            //Collectors.toList() : 在底层会创建一个List集合.并把所有的数据添加到List集合中.
            List<Integer> list = list1.stream().filter(i -> i % 2 == 0)
                    .collect(Collectors.toList());
            System.out.println(list);//[2, 4, 6, 8, 10, 10, 10, 10, 10, 10]
    
            //2.收集到Set中
            Set<Integer> set = list1.stream().filter(i -> i % 2 == 0)
                    .collect(Collectors.toSet());
            System.out.println(set);[2, 4, 6, 8]
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    收集到Map 双列集合中

    案例:
    在这里插入图片描述

        public static void main(String[] args) {
            ArrayList<String > list=new ArrayList<>();
            list.add("zhangsan,23");
            list.add("lisi,24");
            list.add("wangwu,25");
            
    
            //collect和forEach都是终结方法 只能有一个
            /*list.stream().filter(s -> Integer.valueOf(s.split(",")[1])>=24)
                    .forEach(s -> System.out.println(s));*/
            Map<String, Integer> map = list.stream().filter(
                    s -> {
                        String[] split = s.split(",");
                        int age = Integer.parseInt(split[1]);
                        return age >= 24;
                    }
    
                    //collect方法只能获取到流中剩余的每一个数据.
                    //在底层不能创建容器,也不能把数据添加到容器当中
                    //Collectors.toMap 创建一个map集合并将数据添加到集合当中
                        // s 依次表示流中的每一个数据
                        //第一个lambda表达式就是如何获取到Map中的键
                        //第二个lambda表达式就是如何获取Map中的值
            ).collect(Collectors.toMap(
                    (String s) ->{
                        return s.split(",")[0];
                    } ,
                    (String s) -> {
                        return Integer.parseInt(s.split(",")[1]);
                    }
            ));
            System.out.println(map);//{lisi=24, wangwu=25}
    
            //简化写法
            Map<String, Integer> map2 = list.stream().filter(s -> Integer.valueOf(s.split(",")[1]) >= 24)
                    .collect(Collectors.toMap( s->s.split(",")[0] , s->Integer.valueOf(s.split(",")[1]) ));
            System.out.println(map2);//{lisi=24, wangwu=25}
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    在这里插入图片描述

    6、Stream流综合练习【应用】★

    • 案例需求

      现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作

      • 男演员只要名字为3个字的前三人
      • 女演员只要姓杨的,并且不要第一个
      • 把过滤后的男演员姓名和女演员姓名合并到一起
      • 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据

      演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法

    • 代码实现

    演员类

    public class Actor {
        private String name;
        //全参、空参、get/set、toString
    }
    
    • 1
    • 2
    • 3
    • 4

    测试类:

        public static void main(String[] args) {
            ArrayList<String>  manList = new ArrayList<>();
            manList.add("张国立"); manList.add("张晋"); manList.add("刘烨");
            manList.add("郑伊健"); manList.add("徐峥"); manList.add("王宝强");
    
            ArrayList<String>  womanList = new ArrayList<>();
            womanList.add("刘亦菲");  womanList.add("杨紫"); womanList.add("关晓彤");
            womanList.add("张天爱"); womanList.add("杨幂"); womanList.add("赵丽颖");
    
            //男演员只要名字为3个字的前两人
            Stream<String> stream1 = manList.stream().filter(s -> s.length() == 3).limit(2);
    
            //女演员只要姓林的,并且不要第一个
            Stream<String> stream2 = womanList.stream().filter(s -> s.startsWith("杨")).skip(1);
    
            //合并 后封装从对象再打印出对象
            Stream.concat(stream1,stream2).forEach(s -> {
                Actor actor = new Actor(s);
                System.out.println(actor);
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

  • 相关阅读:
    PLC电力载波通讯,一种新的IoT通讯技术
    【project 】软件使用
    深度学习论文: MobileNetV4 - Universal Models for the Mobile Ecosystem及其PyTorch实现
    初始Linux(2):Shell、文件权限
    springboot项目中获取业务功能的导入数据模板文件
    记一次 .NET 某电力系统 内存暴涨分析
    RestTemplate请求头accept-encoding导致乱码
    Linux云服务环境安装-JDK篇
    Babylonjs PointerEventTypes.POINTERMOVE 获取不到模型信息
    集线器与交换机的区别
  • 原文地址:https://blog.csdn.net/hza419763578/article/details/125498737