Stream流

一、语句

1. map(mapToInt,mapToLong,mapToDouble) 转换操作符,把比如A->B,这里默认提供了转int,long,double的操作符

2. flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作比如把 int[]{2,3,4} 拍平 变成 2,3,4 也就是从原来的一个数据变成了3个数据,这里默认提供了拍平成int,long,double的操作符

3. limit 限流操作,比如数据流中有10个 我只要出前3个就可以使用

4. distint 去重操作,对重复元素去重,底层使用了equals方法

5. filter 过滤操作,把不想要的数据过滤

6. skip 跳过操作,跳过某些元素

7. sorted(unordered) 排序操作,对元素排序,前提是实现Comparable接口,当然也可以自定义比较器

8. collect 收集操作,将所有数据收集起来,这个操作非常重要,官方的提供的Collectors 提供了非常多收集器,可以说Stream 的核心在于Collectors

9. count 统计操作,统计最终的数据个数

10. findFirst、findAny 查找操作,查找第一个、查找任何一个 返回的类型为Optional

11. min、max 最值操作,需要自定义比较器,返回数据流中最大最小的值

12. forEach、forEachOrdered 遍历操作,这里就是对最终的数据进行消费了

13. toArray 数组操作,将数据流的元素转换成数组

二、遍历/匹配(foreach/find/match)

          public class StreamTest {

              public static void main(String[] args) {
                  List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);
                  // 遍历输出符合条件的元素
                  list.stream().filter(x -> x > 6).forEach(System.out::println);
                  // 匹配第一个
                  Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
                  // 匹配任意(适用于并行流)
                  Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
                  // 是否包含符合特定条件的元素
                  boolean anyMatch = list.stream().anyMatch(x -> x < 6);
                  System.out.println("匹配第一个值:" + findFirst.get());
                  System.out.println("匹配任意一个值:" + findAny.get());
                  System.out.println("是否存在大于6的值:" + anyMatch);
                  
              }
      }

三、筛选(filter)

        筛选出Integer集合中大于7的元素,并打印出来

        public class StreamTest {

            public static void main(String[] args) {
                List<Integer> list = Arrays.asList(6, 7, 3, 8, 1, 2, 9);
                Stream<Integer> stream = list.stream();
                stream.filter(x -> x > 7).forEach(System.out::println);
            }
        }

四、聚合(max/min/count)

         max、min、count这些字眼你一定不陌生,没错,在mysql中我们常用它们进行数据统计。Java stream中也引入了这些概念和用法,极大地方便了我们对集合、数组的数据统计工作。

        案例一:获取String集合中最长的元素。

        public class StreamTest {

            public static void main(String[] args) {
                List<String> list = Arrays.asList("adnm", "admmt", "pot", "xbangd", "weoujgsd");
                Optional<String> max = list.stream().max(Comparator.comparing(String::length));
                System.out.println("最长的字符串:" + max.get());
            }
        }


        max、min、count这些字眼你一定不陌生,没错,在mysql中我们常用它们进行数据统计。Java stream中也引入了这些概念和用法,极大地方便了我们对集合、数组的数据统计工作。


          案例三:计算Integer集合中大于6的元素的个数。

          public class StreamTest {

              public static void main(String[] args) {
                  List<Integer> list = Arrays.asList(7, 6, 4, 8, 2, 11, 9);
                  long count = list.stream().filter(x -> x > 6).count();
                  System.out.println("list中大于6的元素个数:" + count);
              }
          }

五、映射(map/flatMap)

    映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap:

    map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素

    flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流


        public class StreamTest {

            public static void main(String[] args) {
                String[] strArr = { "abcd", "bcdd", "defde", "fTr" };
                List<String> strList = Arrays.stream(strArr).map(String::toUpperCase).collect(Collectors.toList());
                System.out.println("每个元素大写:" + strList);
                List<Integer> intList = Arrays.asList(1, 3, 5, 7, 9, 11);
                List<Integer> intListNew = intList.stream().map(x -> x + 3).collect(Collectors.toList());
                System.out.println("每个元素+3:" + intListNew);
            }
       }

六、归集(toList/toSet/toMap)

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


        public class StreamTest {

              public static void main(String[] args) {
                  List<Integer> list = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20);
                  List<Integer> listNew = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
                  Set<Integer> set = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet());
                  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"));
                  Map<?, Person> map = personList.stream().filter(p -> p.getSalary() > 8000)
                          .collect(Collectors.toMap(Person::getName, p -> p));
                  System.out.println("toList:" + listNew);
                  System.out.println("toSet:" + set);
                  System.out.println("toMap:" + map);
              }
        }

七、统计(count/averaging)

        Collectors提供了一系列用于数据统计的静态方法:

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


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

       public class StreamTest {

                public static void main(String[] args) {
                    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"));
                    // 求总数
                    long count = personList.size();
                    // 求平均工资
                    Double average = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
                    // 求最高工资
                    Optional<Integer> max = personList.stream().map(Person::getSalary).max(Integer::compare);
                    // 求工资之和
                    int sum = personList.stream().mapToInt(Person::getSalary).sum();
                    // 一次性统计所有信息
                    DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
                    System.out.println("员工总数:" + count);
                    System.out.println("员工平均工资:" + average);
                    System.out.println("员工最高工资:" + max.get());
                    System.out.println("员工工资总和:" + sum);
                    System.out.println("员工工资所有统计:" + collect);
                }
            }   

八、分组(partitioningBy/groupingBy)

        分区:将stream按条件分为两个Map,比如员工按薪资是否高于8000分为两部分
        分组:将集合分为多个Map,比如员工按性别分组。有单级分组和多级分组


        案例:将员工按薪资是否高于8000分为两部分;将员工按性别和地区分组

            public class StreamTest {

                public static void main(String[] args) {
                    List<Person> personList = new ArrayList<Person>();
                    personList.add(new Person("Tom", 8900, 23, "male", "Washington"));
                    personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
                    personList.add(new Person("Lily", 7800, 21, "female", "New York"));
                    personList.add(new Person("Anni", 8200, 24, "female", "New York"));
                    // 将员工按薪资是否高于8000分组
                    Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
                    // 将员工按性别分组
                    Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex));
                    // 将员工先按性别分组,再按地区分组
                    Map<String, Map<String, List<Person>>> group2 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
                    System.out.println("员工按薪资是否大于8000分组情况:" + part);
                    System.out.println("员工按性别分组情况:" + group);
                    System.out.println("员工按性别、地区:" + group2);
                }
            }

九、排序(sorted)

      sorted,中间操作
      有两种排序:
           1、sorted():自然排序,流中元素需实现Comparable接口
           2、sorted(Comparator com):Comparator排序器自定义排序

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

            public class StreamTest {

                public static void main(String[] args) {
                    List<Person> personList = new ArrayList<Person>();
                    personList.add(new Person("Sherry", 9000, 24, "female", "New York"));
                    personList.add(new Person("Tom", 8900, 22, "male", "Washington"));
                    personList.add(new Person("Jack", 9000, 25, "male", "Washington"));
                    personList.add(new Person("Lily", 8800, 26, "male", "New York"));
                    personList.add(new Person("Alisa", 9000, 26, "female", "New York"));
                    // 按工资升序排序(自然排序)
                    List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName)
                            .collect(Collectors.toList());
                    // 按工资倒序排序
                    List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed())
                            .map(Person::getName).collect(Collectors.toList());
                    // 先按工资再按年龄升序排序
                    List<String> newList3 = personList.stream()
                            .sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName)
                            .collect(Collectors.toList());
                    // 先按工资再按年龄自定义排序(降序)
                    List<String> newList4 = personList.stream().sorted((p1, p2) -> {
                        if (p1.getSalary() == p2.getSalary()) {
                            return p2.getAge() - p1.getAge();
                        } else {
                            return p2.getSalary() - p1.getSalary();
                        }
                    }).map(Person::getName).collect(Collectors.toList());
                    System.out.println("按工资升序排序:" + newList);
                    System.out.println("按工资降序排序:" + newList2);
                    System.out.println("先按工资再按年龄升序排序:" + newList3);
                    System.out.println("先按工资再按年龄自定义降序排序:" + newList4);
                }

            }

十、提取/组合

            流也可以进行合并、去重、限制、跳过等操作

            public class StreamTest {

                  public static void main(String[] args) {
                      String[] arr1 = { "a", "b", "c", "d" };
                      String[] arr2 = { "d", "e", "f", "g" };
                      Stream<String> stream1 = Stream.of(arr1);
                      Stream<String> stream2 = Stream.of(arr2);
                      // concat:合并两个流 distinct:去重
                      List<String> newList = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
                      // limit:限制从流中获得前n个数据
                      List<Integer> collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
                      // skip:跳过前n个数据
                      List<Integer> collect2 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());
                      System.out.println("流合并:" + newList);
                      System.out.println("limit:" + collect);
                      System.out.println("skip:" + collect2);
                  }
           }

十一、集合转Map操作

      在实际的开发过程中,还有一个使用最频繁的操作就是,将集合元素中某个主键字段作为key,元素作为value,来实现集合转map的需求,
      这种需求在数据组装方面使用的非常多


       public static void main(String[] args) {
            List<Person> personList = new ArrayList<>();
            personList.add(new Person("Tom",7000,25,"male","安徽"));
            personList.add(new Person("Jack",8000,30,"female","北京"));
            personList.add(new Person("Lucy",9000,40,"male","上海"));
            personList.add(new Person("Airs",10000,40,"female","深圳"));
            Map<Integer, Person> collect = personList.stream().collect(Collectors.toMap(Person::getAge, v -> v, (k1, k2) -> k1));
            System.out.println(collect);
      }
  
     结果:

     {40=Person{name='Lucy', salary=9000, age=40, sex='male', area='上海'}, 25=Person{name='Tom', salary=7000, age=25, sex='male', area='安徽'}, 30=Person{name='Jack', salary=8000, age=30, sex='female', area='北京'}}
上一篇:Java8新特性之Stream--collect方法


下一篇:lamdba03 Java8新特性之四:Stream API