Stream流

体验Stream流【理解】

  • 案例需求

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

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

    java 复制代码
    public class MyStream1 {
        public static void main(String[] args) {
            //集合的批量添加
            ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));
            //list.add()
    
            //遍历list1把以张开头的元素添加到list2中。
            ArrayList<String> list2 = new ArrayList<>();
            for (String s : list1) {
                if(s.startsWith("张")){
                    list2.add(s);
                }
            }
            //遍历list2集合,把其中长度为3的元素,再添加到list3中。
            ArrayList<String> list3 = new ArrayList<>();
            for (String s : list2) {
                if(s.length() == 3){
                    list3.add(s);
                }
            }
            for (String s : list3) {
                System.out.println(s);
            }      
        }
    }
  • 使用Stream流示例代码

    java 复制代码
    public class StreamDemo {
        public static void main(String[] args) {
            //集合的批量添加
            ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));
    
            //Stream流
            list1.stream().filter(s->s.startsWith("张"))
                    .filter(s->s.length() == 3)
                    .forEach(s-> System.out.println(s));
        }
    }
  • Stream流的好处

    • 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印
    • Stream流把真正的函数式编程风格引入到Java中
    • 代码简洁

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

  • Stream流的思想

  • Stream流的三类方法

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

    • Collection体系集合

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

    • Map体系集合

      把Map转成Set集合,间接的生成流

    • 数组

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

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

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

  • 代码演示

    java 复制代码
    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<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() 返回由该流的不同元素(根据Object.equals(Object) )组成的流
    Stream<R> map(Funtion<T,R> mapper) 转换流中的数据类型

注意1: 中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
注意2: 修改Stream流中的数据,不会影响原来集合或者数组中的数据

  • filter代码演示

    java 复制代码
    public class MyStream3 {
        public static void main(String[] args) {
    //        Stream<T> filter(Predicate predicate):过滤
    //        Predicate接口中的方法	boolean test(T t):对给定的参数进行判断,返回一个布尔值
    
            ArrayList<String> list = new ArrayList<>();
            list.add("张三丰");
            list.add("张无忌");
            list.add("张翠山");
            list.add("王二麻子");
            list.add("张良");
            list.add("谢广坤");
    
            //filter方法获取流中的 每一个数据.
            //而test方法中的s,就依次表示流中的每一个数据.
            //我们只要在test方法中对s进行判断就可以了.
            //如果判断的结果为true,则当前的数据留下
            //如果判断的结果为false,则当前数据就不要.
    //        list.stream().filter(
    //                new Predicate<String>() {
    //                    @Override
    //                    public boolean test(String s) {
    //                        boolean result = s.startsWith("张");
    //                        return result;
    //                    }
    //                }
    //        ).forEach(s-> System.out.println(s));
    
            //因为Predicate接口中只有一个抽象方法test
            //所以我们可以使用lambda表达式来简化
    //        list.stream().filter(
    //                (String s)->{
    //                    boolean result = s.startsWith("张");
    //                        return result;
    //                }
    //        ).forEach(s-> System.out.println(s));
    
            list.stream().filter(s ->s.startsWith("张")).forEach(s-> System.out.println(s));
    
        }
    }
  • limit&skip代码演示

    java 复制代码
    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(s-> System.out.println(s));
            System.out.println("--------");
    
            //需求2:跳过3个元素,把剩下的元素在控制台输出
            list.stream().skip(3).forEach(s-> System.out.println(s));
            System.out.println("--------");
    
            //需求3:跳过2个元素,把剩下的元素中前2个在控制台输出
            list.stream().skip(2).limit(2).forEach(s-> System.out.println(s));
        }
    }
  • concat&distinct代码演示

    java 复制代码
    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(s-> System.out.println(s));
    
            //需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
            Stream.concat(s1,s2).distinct().forEach(s-> System.out.println(s));
        }
    }
  • map代码演示

    java 复制代码
    public class StreamDemo4 {
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<>();
            Collections.addAll(list, "张无忌-15", "周芷若-14", "赵敏-13", "张强-20", "张三丰-100", "张翠山-40", "张良-35", "王二麻子-37", "谢广坤-41");
            //需求:只获取里面的年龄并进行打印
            //String->int
    
            //第一个类型:流中原本的数据类型
            //第二个类型:要转成之后的类型
    
            //apply的形参s:依次表示流里面的每一个数据
            //返回值:表示转换之后的数据
    
            //当map方法执行完毕之后,流上的数据就变成了整数
            //所以在下面forEach当中,s依次表示流里面的每一个数据,这个数据现在就是整数了
            list.stream().map(new Function<String, Integer>() {
                @Override
                public Integer apply(String s) {
                    String[] arr = s.split("-");
                    String ageString = arr[1];
                    int age = Integer.parseInt(ageString);
                    return age;
                }
            }).forEach(s-> System.out.println(s));
    
            System.out.println("------------------------");
    
            list.stream()
                    .map(s-> Integer.parseInt(s.split("-")[1]))
                    .forEach(s-> System.out.println(s));
        }
    }

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

  • 概念

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

  • 常见方法

    方法名 说明
    void forEach(Consumer action) 对此流的每个元素执行操作
    long count() 返回此流中的元素数
    toArray() 收集流中的数据,放到数组中
    collect(Collector collector) 收集流中的数据,放到集合中
  • 代码演示

    java 复制代码
    public class StreamDemo5 {
       public static void main(String[] args) {
          /*
               void forEach(Consumer action)           遍历
               long count()                            统计
               toArray()                               收集流中的数据,放到数组中
          */
    
           ArrayList<String> list = new ArrayList<>();
           Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");
    
    
           //void forEach(Consumer action)           遍历
    
           //Consumer的泛型:表示流中数据的类型
           //accept方法的形参s:依次表示流里面的每一个数据
           //方法体:对每一个数据的处理操作(打印)
           /*list.stream().forEach(new Consumer<String>() {
               @Override
               public void accept(String s) {
                   System.out.println(s);
               }
           });*/
    
           //list.stream().forEach(s -> System.out.println(s));
    
    
    
           // long count()                            统计
           //long count = list.stream().count();
           //System.out.println(count);
    
    
    
           // toArray()                               收集流中的数据,放到数组中
           //Object[] arr1 = list.stream().toArray();
           //System.out.println(Arrays.toString(arr1));
    
           //IntFunction的泛型:具体类型的数组
           //apply的形参:流中数据的个数,要跟数组的长度保持一致
           //apply的返回值:具体类型的数组
           //方法体:就是创建数组
    
    
           //toArray方法的参数的作用:负责创建一个指定类型的数组
           //toArray方法的底层,会依次得到流里面的每一个数据,并把数据放到数组当中
           //toArray方法的返回值:是一个装着流里面所有数据的数组
          /* String[] arr = list.stream().toArray(new IntFunction<String[]>() {
               @Override
               public String[] apply(int value) {
                   return new String[value];
               }
           });
    
           System.out.println(Arrays.toString(arr));*/
           String[] arr2 = list.stream().toArray(value -> new String[value]);
           System.out.println(Arrays.toString(arr2));
       }
    }

Stream流的收集操作【应用】

  • 概念

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

  • 常用方法

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

    方法名 说明
    public static <T> Collector toList() 把元素收集到List集合中
    public static <T> Collector toSet() 把元素收集到Set集合中
    public static Collector toMap(Function keyMapper,Function valueMapper) 把元素收集到Map集合中
  • 代码演示

    java 复制代码
    public class StreamDemo10 {
       public static void main(String[] args) {
    
           /*
               collect(Collector collector)            收集流中的数据,放到集合中 (List Set Map)
    
               注意点:
                   如果我们要收集到Map集合当中,键不能重复,否则会报错
          */
    
           ArrayList<String> list = new ArrayList<>();
           Collections.addAll(list, "张无忌-男-15", "周芷若-女-14", "赵敏-女-13", "张强-男-20",
                   "张三丰-男-100", "张翠山-男-40", "张良-男-35", "王二麻子-男-37", "谢广坤-男-41");
    
    
           //收集List集合当中
           //需求:
           //我要把所有的男性收集起来
           List<String> newList1 = list.stream()
                   .filter(s -> "男".equals(s.split("-")[1]))
                   .collect(Collectors.toList());
           //System.out.println(newList1);
    
    
           //收集Set集合当中
           //需求:
           //我要把所有的男性收集起来
           Set<String> newList2 = list.stream().filter(s -> "男".equals(s.split("-")[1]))
                   .collect(Collectors.toSet());
           //System.out.println(newList2);
    
    
           //收集Map集合当中
           //谁作为键,谁作为值.
           //我要把所有的男性收集起来
           //键:姓名。 值:年龄
           Map<String, Integer> map = list.stream()
                   .filter(s -> "男".equals(s.split("-")[1]))
                   /*
                    *   toMap : 参数一表示键的生成规则
                    *           参数二表示值的生成规则
                    *
                    * 参数一:
                    *       Function泛型一:表示流中每一个数据的类型
                    *               泛型二:表示Map集合中键的数据类型
                    *
                    *        方法apply形参:依次表示流里面的每一个数据
                    *               方法体:生成键的代码
                    *               返回值:已经生成的键
                    *
                    *
                    * 参数二:
                    *        Function泛型一:表示流中每一个数据的类型
                    *                泛型二:表示Map集合中值的数据类型
                    *
                    *       方法apply形参:依次表示流里面的每一个数据
                    *               方法体:生成值的代码
                    *               返回值:已经生成的值
                    *
                    * */
                   .collect(Collectors.toMap(new Function<String, String>() {
                                                 @Override
                                                 public String apply(String s) {
                                                     //张无忌-男-15
                                                     return s.split("-")[0];
                                                 }
                                             },
                           new Function<String, Integer>() {
                               @Override
                               public Integer apply(String s) {
                                   return Integer.parseInt(s.split("-")[2]);
                               }
                           }));
    
    
           Map<String, Integer> map2 = list.stream()
                   .filter(s -> "男".equals(s.split("-")[1]))
                   .collect(Collectors.toMap(
                           s -> s.split("-")[0],
                           s -> Integer.parseInt(s.split("-")[2])));
           System.out.println(map2);
       }
    }
相关推荐
XiaoLeisj31 分钟前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck32 分钟前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei32 分钟前
java的类加载机制的学习
java·学习
Yaml42 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~2 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616883 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
aloha_7893 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
记录成长java4 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
睡觉谁叫~~~4 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust
程序媛小果4 小时前
基于java+SpringBoot+Vue的旅游管理系统设计与实现
java·vue.js·spring boot