• 08-Stream流计算


    Stream流计算

    用传统for循环处理复杂计算代码虽然也不是很难,但代码就显得冗余了。跟Stream相比就显而易见。配合出现的Lambda表达式,给我们操作集合类提供了方便。

    在这里插入图片描述

    定义
    Stream将要处理的元素集合看作一种流,在流的过程。借助Stream对流中的元素进行操作,比如筛选、排序、集合等‘
    Stream可以由数组或集合创建。对流的操作分为两种:

    1. 中间操作,每次返回一个新的流,可以有多个
    2. 终端操作,每个流只能进行一次终端操作,终端操作后流无法再次使用,终端操作后会产生一个新的集合或值

    另外,Stream有几个新的特性:

    1. Stream不存储元素,而是按照特定的规则对数据进行计算,一般会输出i结果。
    2. Stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
    3. Stream具有延迟特性,只有终端操作时,中间操作才会执行
    Stream可以通过集合数组创建

    stream()

     List<String> list=new ArrayList<>();
            list.add("A");
            list.add("B");
            list.add("C");
            Stream<String> stream = list.stream();//创建一个顺序流
            System.out.println(stream);
    
           //创建一个并行流
            Stream<String> stringStream = list.parallelStream();
            System.out.println(stringStream);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    结果:
    在这里插入图片描述

    用数组创建流

    Arrays.stream();

      int [] array={1,3,5,7,9};
            IntStream stream1 = Arrays.stream(array);
            System.out.println(stream1);
    
    • 1
    • 2
    • 3

    结果:
    在这里插入图片描述

    Stream静态方法

    of(); 、 iterator();、generate();
    在这里插入图片描述

            Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
            System.out.println(integerStream);
            
            System.out.println("=================");
            Stream<Integer> limit = Stream.iterate(1, (x) -> x + 2).limit(5);//打印从1 每次加2,数量为5
            limit.forEach(System.out::println);
            System.out.println("=================");
            
            Stream<Double> limit1 = Stream.generate(Math::random).limit(3);//随机生成个3个小数
            limit1.forEach(System.out::println);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    结果:
    在这里插入图片描述

    Stream和parallelStream的区别
    1. Stream事顺序流,由主线程按顺序对流进行操作。
    2. parallelStream是并行流,内部以多线程并执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求
      筛选集合中的奇数,两种处理方式是不同的:

    在这里插入图片描述
    如果流中的数据量足够大,并行流可以加快速度,除了直接创建并行流。还可以通过parallel()把顺序流转换成并行流:

    在使用stream之前,先理解Optional的概念

    Optional类是一个可以为null的容器对象。如果值存在则isPresent()方法返回true,调用get()方法返回该对象。
    详解见 :菜鸟教程Java 8 Optional类

    List list=new ArrayList<>();
            list.add(8);
            list.add(9);
            list.add(1);
            list.add(3);
            //筛选大于6 的第一个数字
            Optional<Integer> s= list.stream().parallel().filter(x->x>6).findFirst();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    遍历
     List<Integer> list= Arrays.asList(1,2,3,4,5,6,7,8,9);
            //筛选所有大于7的数字
            list.stream().filter(x->x>7).forEach(System.out::println);
            System.out.println("========");
    
            //匹配第一个大于1的数字
            Optional<Integer> first = list.stream().filter(x->x>1).findFirst();
            System.out.println(first.get());
            System.out.println("========");
    
            //匹配任意一个大于1的数字
            Optional<Integer> any = list.parallelStream().filter(x -> x > 1).findAny();
            System.out.println(any.get());
            System.out.println("========");
    
            boolean b = list.stream().anyMatch(x -> x > 7);
            System.out.println(b);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    结果:
    在这里插入图片描述

    筛选

    筛选是按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中。
    在这里插入图片描述

    将用多个案例帮助理解使用Stream

    Person类:

    @Data
    @AllArgsConstructor
    public class Person {
        private String name;
        private Integer age;
        private String sex;
        private Double salary;
        private String area;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
      List<Person> personList=new ArrayList<>();
            personList.add(new Person("张三",20,"男",8900.00,"江苏盐城"));
            personList.add(new Person("李四",21,"男",7000.00,"江苏镇江"));
            personList.add(new Person("王五",22,"男",7800.00,"江苏常州"));
            personList.add(new Person("张丽",23,"女",8200.00,"江苏淮安"));
            personList.add(new Person("王茜",24,"女",9500.00,"江苏南通"));
            personList.add(new Person("陈涵",22,"女",7900.00,"江苏南京"));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    筛选员工中工资高于8000的人,形成新的集合。形成的集合使用collect()收集。

    List<Person> collect =personList.stream.filter(person-> person.getSalary()>8000).collect(Collector.toList);
    System.out.println(collect);
    
    • 1
    • 2

    结果:
    在这里插入图片描述

    聚合

    max、min、result
    在这里插入图片描述

    案例1:获取String 中最长的元素值

      List<String> ListA=Arrays.asList("Admin","Test","Manager","Develop");
      Optional<String>max=ListA.stream.max(Compatrator.comparing(String::length));
      System.out.println(max.get());
    
    • 1
    • 2
    • 3

    结果:
    在这里插入图片描述
    案例2 获取集合中最大的值

     List<Integer> integerList=Arrays.asList(1,3,5,7,2,4);
     
     Optional<Integer> max=integerList.stream.max(Integer::compareTo);
     System.out.println(max.get());
    
    • 1
    • 2
    • 3
    • 4

    结果:
    在这里插入图片描述
    案例3
    获取员工中最高工资的人

    Optional<Person> max=personList.stream.max(Comparator.comparing(person->person.getSalary()));
    System.out.println(max.get());
    //第二种方法
    Optional<Person> max1=personList.stream.max(Comparator.comparingDouble(Person::getSalary)));
    System.out.println(max1.get());
    
    • 1
    • 2
    • 3
    • 4
    • 5

    结果:
    在这里插入图片描述
    案例四
    计算集合中元素大于6的个数

    List<Integer> integerList=Arrays.asList(1,2,3,4,5,6,7,8,9);
    
    Long count=integerList.stream.filter(i->i>6).count();
    System.out.println(count);
    
    • 1
    • 2
    • 3
    • 4

    结果:
    在这里插入图片描述

    3.4映射

    map/flatmap
    可以将一个流的元素按照一定的规则映射到另一个流的元素上,分为map和flatmap

    1. map:接受一个函数作为参数,将其映射成一个新的元素
    2. flatMap:接收一个函数作为参数,将流中的每一个值都换成另一个流,然后将所有的流连接起来变成另一个流。
      在这里插入图片描述
      案例1英文字符数组元素全部改为大写,整数数组每个元素+3
    String[] arr={"cdc","cwerec","ggfb"};
    List<String> collect=Arrays.asList(arr).stream().map(String::toUpperCase).collect(Collectors.toList());
    System.out.println(collect);
    
    List<Integer> integerList=Arrays.asList(1,5,7);
    List<Integer>collect1=integer.stream.map(i->i+3).collect(Collector.toList));
    System.out.println(collect1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    结果:
    在这里插入图片描述
    案例2: 将员工的工资全部增加1000

    List<Person> newList=personList.stream.map(person->{
     person.setSalary(person.getSalary+1000.00);
     return person;
    }).collect(Collector.toList);
    
    System.out.println(newList);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    结果:
    在这里插入图片描述
    案例3
    将两个字符组合成一个新的字符数组

     List<String> list= Arrays.asList("m,k,l,a","1,3,5,7");
            List<String> list_new1 = list.stream().flatMap(words -> {
                String[] split = words.split(",");
                Stream<String> list_new = Arrays.stream(split);
                return list_new;
            }).collect(Collectors.toList());
    
            System.out.println("原始list"+list);
            System.out.println("新的"+list_new1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    结果:
    在这里插入图片描述

    3.5归约

    归约也就是缩减,将一个流缩减成一个值,能实现对集合的求值、求乘机和求和、求最值的操作

    案例一:求Integer集合的元素之和、乘机和最大值

            List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
            Optional<Integer> sum = integers.stream().reduce(Integer::sum);
    
            Optional<Integer> multi = integers.stream().reduce((x, y) ->x*y);
    
    //方式1
            Integer max = integers.stream().reduce(1, Integer::max);
            //方式2
            Optional<Integer> max1 = integers.stream().max(Comparator.comparing(Integer::intValue));
            //方式3
            Optional<Integer> max2 = integers.stream().max(Integer::compareTo);
    
            System.out.println("和"+sum.get());
            System.out.println("乘"+multi);
            System.out.println("最大值"+max2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    结果:
    在这里插入图片描述
    案例二:
    求所有员工的工资之和和最高的工资

        List<Person> personList=new ArrayList<Person>();
            personList.add(new Person("Tom", 8900, 23, "male", "New York"));
            personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
            personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
            personList.add(new Person("Anni", 8200, 24, "female", "New York"));
            personList.add(new Person("Owen", 9500, 25, "male", "New York"));
            personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
    
            Optional<Integer> sum = personList.stream().map(Person::getSalary).reduce(Integer::sum);
            Optional<Person> max = personList.stream().max(Comparator.comparing(Person::getSalary));
            System.out.println("总和"+sum);
            System.out.println("最大值"+max.get().getSalary());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    结果:
    在这里插入图片描述

    3.6 收集(collect)

    collect,收集,把流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。

    • collect主要依赖java.util.stream.Collectors类内置的静态方法。

    3.6.1
    归集(toList/toSet/toMap)
    因为流不存储数据,那么流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toList、toSet和toMap比较常用,另外还有toCollection、toConcurrentMap等复杂的一些用法。

    案例一:

      List<Integer> list=Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
            List<Integer> new_list = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
            Set<Integer> new_Set = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet());
            Map<String, Person> new_Map = personList.stream().filter(person ->
                    person.getSalary() > 8000
            ).collect(Collectors.toMap(Person::getName, person -> person));
    
            System.out.println("list"+new_list);
            System.out.println("set"+new_Set);
            System.out.println("map"+new_Map);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    结果:
    在这里插入图片描述
    3.6.2统计(count/averaging)
    Collectors提供了一系列用于数据统计的静态方法:

    • 计数count
    • 平均值:averagingint、averagingLong、averagingDouble
    • 最值:maxBy、minBy
    • 求和:summingInt 、summingLong、summingDouble
    • 统计以上所有:summarizingInt、summarizingLong、summarizingDouble

    案例:统计员工人数、平均工资、工资总额、最高工资等

      Long count = personList.stream().collect(Collectors.counting());
            Double salary = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
            Optional<Integer> max = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compareTo));
            IntSummaryStatistics sum = personList.stream().collect(Collectors.summarizingInt(Person::getSalary));
            DoubleSummaryStatistics sumAll = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
    
            System.out.println("数量"+count);
            System.out.println("平均工资"+salary);
            System.out.println("最高工资"+max);
            System.out.println("工资之和"+sum);
            System.out.println("一次性信息"+sumAll);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    结果:
    在这里插入图片描述

    3.6.3分组(partitioningBy/groupingBy)
    • 分区:将stream按条件分为两个Map,比如员工按薪资是否高于8000分为部分
    • 分组:将集合分为多个Map,比如员工按性别分组,有单级分组和多级分组。
      在这里插入图片描述
      案例
      将员工按薪资是否高于8000分为两部分;将员工按性别和地区分组
            Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
            Map<String, List<Person>> part1 = personList.stream().collect(Collectors.groupingBy(Person::getSex));
            Map<String, Map<String, List<Person>>> part3 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getSex)));
    
            System.out.println("员工按薪资是否大于8000分组情况"+part);
            System.out.println("员工按性别分组情况"+part1);
            System.out.println("员工按性别、地区分组情况"+part3);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    结果:
    在这里插入图片描述

    3.6.4接合(joining)

    joining可以将stream中的元素用特定的连接符连接成一个字符串。

            String joinName = personList.stream().map(person -> person.getName()).collect(Collectors.joining("-"));
    
            List<String> list = Arrays.asList("A", "B", "C");
            String collect = list.stream().collect(Collectors.joining("+"));
    
            System.out.println("所有员工的姓名"+joinName);
            System.out.println("拼接后的字符串"+collect);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    结果:
    在这里插入图片描述

    3.6.5归约(reducing)

    Collectors类提供的reducing方法,相比于stream本身的reduce方法,增加了对于自定义归约的支持。

    Optional<Integer> sumSalary = personList.stream().map(Person::getSalary).reduce(Integer::sum);
            Integer sum = personList.stream().collect(Collectors.summingInt(Person::getSalary));
            System.out.println("员工薪资总和"+sumSalary.get());
            System.out.println("员工薪资总和"+sum);
    
    • 1
    • 2
    • 3
    • 4

    结果:
    在这里插入图片描述

    3.7排序(sorted)
    • sorted():自然排序,流中元素实现Comparable
    • sorted(Comparator com):Comparator排序器自定义排序

    案例:将员工按工资由高到低(工资一样则年龄由大到小)排序

     //自然排序
            List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary))
                    .map(Person::getName).collect(Collectors.toList());
    
            //倒序排序
            List<String> newList1 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed())
                    .map(Person::getName).collect(Collectors.toList());
    
            //先按工资再按年龄升序排序
            List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary)
                            .thenComparing(Person::getAge)).map(Person::getName)
                    .collect(Collectors.toList());
    
            System.out.println("升序排序"+newList);
            System.out.println("降序排序"+newList1);
            System.out.println("先按工资再按年龄升序排序"+newList2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    结果:
    在这里插入图片描述

    3.8提取、组合

    流也可以进行合并、去重、限制、跳过等操作
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

            String[] arr1={"a","b","c","d"};
            String[] arr2={"d","e","f","g"};
    
            //去重
            List<String> distinct = Stream.concat(Stream.of(arr1), Stream.of(arr2)).
                                    distinct().collect(Collectors.toList());
    
            //限制从流中获取n个数字
            List<Integer> collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
    
            List<Integer> collect1 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());
    
            System.out.println("流合并"+distinct);
            System.out.println("limit"+collect);
            System.out.println("skip"+collect1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    结果:
    在这里插入图片描述

  • 相关阅读:
    Leetcode581. 最短无序连续子数组
    java计算机毕业设计衣依服装销售平台源码+系统+数据库+lw文档
    2022年湖北中级工程师职称可以评哪些专业?甘建二
    gitee git 打一个 tag
    elasticsearch代码基本实现
    电脑电源灯一闪一闪开不了机怎么办
    Java代码规范
    npm run dev和npm run serve两个命令的区别
    Navicat 强大的数据模型功能 | 面向数据库设计、架构和数据资产梳理等使用场景
    零基础学Java一定要注意这些问题!
  • 原文地址:https://blog.csdn.net/niannujiao6/article/details/126234136