Java8新特性之Stream

 

  1. Stream是对集合操作的增强,流不是集合的元素,不是一种数据结构,不负责数据的存储。流更像一个迭代器,可以单项的遍历一个集合中的元素,并且不可循环。对于使用角度而言,个人觉得最大的好处就是简化代码量。
  2. 使用流式编程的步骤
    1.   获取数据源,将数据源中的数据读取到流中
    2. (中间操作)对流中的数据进行各种各样的处理。如过滤、去重、排序、替换等操作
    3. (最终操作)对流中的数据进行整合处理
  3. 数据源的获取
    1.   常用的数据源是集合或者数组
    2. 集合:list.stream()
    3. 数组:Arrays.stream(arr1)
  4. 中间操作
    1.   提前预制数据:
      private static class Student implements Comparable<Student> {
              int id;
              int score;
              String name;
      
              @Override
              public boolean equals(Object o) {
                  if (this == o) return true;
                  if (o == null || getClass() != o.getClass()) return false;
                  Student student = (Student) o;
                  return id == student.id &&
                          score == student.score &&
                          Objects.equals(name, student.name);
              }
      
              @Override
              public int hashCode() {
                  return Objects.hash(id, score, name);
              }
      
              public Student(int id, int score, String name) {
                  this.id = id;
                  this.score = score;
                  this.name = name;
              }
      
              @Override
              public String toString() {
                  return "Student{" +
                          "id=" + id +
                          ", score=" + score +
                          ", name='" + name + '\'' +
                          '}';
              }
      
              public int getId() {
                  return id;
              }
      
              public int getScore() {
                  return score;
              }
      
              public String getName() {
                  return name;
              }
      
              @Override
              public int compareTo(Student o) {
                  return score - o.getScore();
              }
          }

       

      public Stream<Student> getDataSource1() {
              List<Student> students = new ArrayList<>();
              Collections.addAll(students, new Student(1, 90, "zhangsan"),
                      new Student(1, 90, "lisi"),
                      new Student(2, 80, "wangwu"),
                      new Student(3, 85, "zhaoliu"),
                      new Student(4, 80, "qianqi"),
                      new Student(4, 80, "qianqi"),
                      new Student(5, 90, "liuba"));
              return students.stream();
          }
    2. 每进行一个中间操作,还会得到一个流,即可以一直使用中间操作,直到使用最终操作来终止流
    3. filter:条件过滤
      1. 仅保留符合条件的数据,不符合的将会被删除
      2. @Test
            public void filterUsage() {
                Stream<Student> dataSource1 = getDataSource1();
                dataSource1.filter(s -> s.getScore() > 80).forEach(System.out::println);
            }

        结果:Student{id=1, score=90, name='zhangsan'}
        Student{id=1, score=90, name='lisi'}
        Student{id=3, score=85, name='zhaoliu'}
        Student{id=5, score=90, name='liuba'}

    4. distinct:进行去重。其去重规则和HashSet的原理相同,故要重写equals()和hashCode()
      1. @Test
            public void distinctUsage() {
                Stream<Student> dataSource1 = getDataSource1();
                dataSource1.distinct().forEach(System.out::println);
            }

        结果:将Student{id=4, score=80, name='qianqi'}去除一个

        Student{id=1, score=90, name='zhangsan'}
        Student{id=1, score=90, name='lisi'}
        Student{id=2, score=80, name='wangwu'}
        Student{id=3, score=85, name='zhaoliu'}
        Student{id=4, score=80, name='qianqi'}
        Student{id=5, score=90, name='liuba'}

    5. sorted: 进行排序
      1. @Test
            public void sorted() {
                Stream<Student> dataSource1 = getDataSource1();
                // 采用该类重写的排序方法进行排序
                dataSource1.sorted().forEach(System.out::println);
                // 自定义排序规则
        //        dataSource1.sorted((s1, s2) -> s2.getScore() - s1.getScore()).forEach(System.out::println);
            }

         

    6. limit&skip
      1.   limit:从0开始截取,一直到指定的参数位置
      2. skip:从指定的参数位置开始截取
      3. 两者经常结合使用,如获取:当score从高往低排序时,截取[3,5]的信息
        @Test
            public void limitAndSkipUsage() {
                Stream<Student> dataSource1 = getDataSource1();
                dataSource1.sorted((s1,s2)->s2.score-s1.score).limit(5).skip(2).forEach(System.out::println);
            }

        结果:

        Student{id=5, score=90, name='liuba'}
        Student{id=3, score=85, name='zhaoliu'}
        Student{id=2, score=80, name='wangwu'}

    7. map&flatmap
      1.   map对流中的元素进行映射,用新的数据来代替旧的数据
      2. flatmap也是对集合中的元素来进行映射,通常来进行扁平化映射:对于map进行直接映射完成后,流中的数据是一个容器,而我们需要对流中的数据进行处理,此时,可以使用扁平化映射,将容器中元素直接存入到流中
      3. @Test
        public void mapUsage() {
        // 将流中的student对象,映射成对象的name
        Stream<Student> dataSource1 = getDataSource1();
        dataSource1.map(Student::getName).forEach(System.out::println);
        }

        结果:

        zhangsan
        lisi
        wangwu
        zhaoliu
        qianqi
        qianqi
        liuba

        /**
             * 需求:统计字符串中出现的所有字符
             */
            @Test
            public void flatMapUsage(){
                String [] arr1 = {"zhangsan","lisi"};
                // 流经过map之后,变成一个容器,此时可用扁平化映射
                Arrays.stream(arr1).map(x->x.split("")).flatMap(Arrays::stream).distinct().forEach(System.out::print);
            }

        结果:zhangsli

  5. 最终操作
    1.   将流中的数据整合到一起,可以放入集合中,也可以遍历打印、数据统计...
    2. 注意:之所以叫最终操作,是因为,执行完之后,流会关闭,且流中的数据也全都会被销毁,此时如果再使用中间操作或者最终操作,就会报异常
    3. collect:将流中的数据收集起来,其参数是一个Collector接口,且这个接口并不是函数式接口,实现这个接口,可以自定义收集的规则,但大多数情况下都是不必定义规则,直接使用Collectors工具提供的方法即可。准备数据:
      // 获取数据源
          public Stream<Integer> getDataSource() {
              List<Integer> integers = new ArrayList<>();
              Collections.addAll(integers, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
              return integers.stream();
          }

       

      1.   转成list、set、map:
        /**
             *转成list、set、map
             */
            @Test
            public void collectUsage() {
                Stream<Integer> dataSource = getDataSource();
        //        List<Integer> collect = dataSource.collect(Collectors.toList());
        //        System.out.println(collect);
        //        Set<Integer> collect = dataSource.collect(Collectors.toSet());
        //        System.out.println(collect);
                Map<String, Integer> collect = dataSource.collect(Collectors.toMap(Object::toString, x -> x));
                System.out.println(collect);
            }

         

      2. reduce:将流中的数据按照某种规则收集起来。如求和
        @Test
            public void reduceUsage() {
                Stream<Integer> dataSource = getDataSource();
                Integer integer = dataSource.reduce(Integer::sum).get();
                System.out.println(integer);
            }

         

      3. count:求流中元素的个数
        @Test
            public void countUsage() {
                Stream<Integer> dataSource = getDataSource();
                long count = dataSource.count();
                System.out.println(count);
            }

         

      4. forEach:循环遍历打印流中的元素
        @Test
            public void forEachUsage() {
                Stream<Integer> dataSource = getDataSource();
                dataSource.forEach(System.out::println);
            }

         

      5. max&min求流中的最大值和最小值
        @Test
            public void maxAndMinUsage() {
                Stream<Integer> dataSource = getDataSource();
        //        Integer integer = dataSource.max(Integer::compareTo).get();
                Integer integer = dataSource.min(Integer::compareTo).get();
                System.out.println(integer);
            }

         

      6. Matching:分为allMatch、anyMatch、noneMatch
        1. allMatch当所有元素都符合条件,则返回true
        2. anyMatch当有任一个元素符合条件,都返回true
        3. noneMatch当所有元素都不符合元素时,才返回true
          @Test
              public void matchUsage() {
                  Stream<Integer> dataSource = getDataSource();
          //        boolean b = dataSource.allMatch(x -> x <10);
          //        boolean b = dataSource.anyMatch(x -> x >= 9);
                  boolean b = dataSource.noneMatch(x -> x > 10);
                  System.out.println(b);
              }

           

      7. find
        1.   findFirst从流中获取一个元素(一般指第一个)
        2. findAny从流中获取一个元素(串行流stream是获取第一个,并行流parallelStream则不一定)
          @Test
              public void findUsage() {
                  Stream<Integer> dataSource = getDataSource();
                  Integer integer = dataSource.findFirst().get();
                  System.out.println(integer);
              }
      8.  相关类:

        package stream;
        
        import org.junit.jupiter.api.Test;
        
        import java.util.*;
        import java.util.stream.Collectors;
        import java.util.stream.Stream;
        
        /**
         * 简单描述
         *
         * @author lijie
         * @data 2021/2/17 21:32
         */
        public class FinalOperation {
            // 获取数据源
            public Stream<Integer> getDataSource() {
                List<Integer> integers = new ArrayList<>();
                Collections.addAll(integers, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
                return integers.stream();
            }
        
            private static class Student implements Comparable<Student> {
                int id;
                int score;
                String name;
        
                @Override
                public boolean equals(Object o) {
                    if (this == o) return true;
                    if (o == null || getClass() != o.getClass()) return false;
                    Student student = (Student) o;
                    return id == student.id &&
                            score == student.score &&
                            Objects.equals(name, student.name);
                }
        
                @Override
                public int hashCode() {
                    return Objects.hash(id, score, name);
                }
        
                public Student(int id, int score, String name) {
                    this.id = id;
                    this.score = score;
                    this.name = name;
                }
        
                @Override
                public String toString() {
                    return "Student{" +
                            "id=" + id +
                            ", score=" + score +
                            ", name='" + name + '\'' +
                            '}';
                }
        
                public int getId() {
                    return id;
                }
        
                public int getScore() {
                    return score;
                }
        
                public String getName() {
                    return name;
                }
        
                @Override
                public int compareTo(Student o) {
                    return score - o.getScore();
                }
            }
        
            public Stream<Student> getDataSource1() {
                List<Student> students = new ArrayList<>();
                Collections.addAll(students, new Student(1, 90, "zhangsan"),
                        new Student(1, 90, "lisi"),
                        new Student(2, 80, "wangwu"),
                        new Student(3, 85, "zhaoliu"),
                        new Student(4, 80, "qianqi"),
                        new Student(4, 80, "qianqi"),
                        new Student(5, 90, "liuba"));
                students.parallelStream()
                return students.stream();
            }
        
            /**
             *转成list、set、map
             */
            @Test
            public void collectUsage() {
                Stream<Integer> dataSource = getDataSource();
        //        List<Integer> collect = dataSource.collect(Collectors.toList());
        //        System.out.println(collect);
        //        Set<Integer> collect = dataSource.collect(Collectors.toSet());
        //        System.out.println(collect);
                Map<String, Integer> collect = dataSource.collect(Collectors.toMap(Object::toString, x -> x));
                System.out.println(collect);
            }
        
            @Test
            public void reduceUsage() {
                Stream<Integer> dataSource = getDataSource();
                Integer integer = dataSource.reduce(Integer::sum).get();
                System.out.println(integer);
            }
        
            @Test
            public void countUsage() {
                Stream<Integer> dataSource = getDataSource();
                long count = dataSource.count();
                System.out.println(count);
            }
        
            @Test
            public void forEachUsage() {
                Stream<Integer> dataSource = getDataSource();
                dataSource.forEach(System.out::println);
            }
        
            @Test
            public void maxAndMinUsage() {
                Stream<Integer> dataSource = getDataSource();
        //        Integer integer = dataSource.max(Integer::compareTo).get();
                Integer integer = dataSource.min(Integer::compareTo).get();
                System.out.println(integer);
            }
        
            @Test
            public void matchUsage() {
                Stream<Integer> dataSource = getDataSource();
        //        boolean b = dataSource.allMatch(x -> x <10);
        //        boolean b = dataSource.anyMatch(x -> x >= 9);
                boolean b = dataSource.noneMatch(x -> x > 10);
                System.out.println(b);
            }
        
            @Test
            public void findUsage() {
                Stream<Integer> dataSource = getDataSource();
                Integer integer = dataSource.findFirst().get();
                System.out.println(integer);
            }
        
            @Test
            public void filterUsage() {
                Stream<Student> dataSource1 = getDataSource1();
                dataSource1.filter(s -> s.getScore() > 80).forEach(System.out::println);
            }
        
            @Test
            public void distinctUsage() {
                Stream<Student> dataSource1 = getDataSource1();
                dataSource1.distinct().forEach(System.out::println);
            }
        
            @Test
            public void sorted() {
                Stream<Student> dataSource1 = getDataSource1();
                // 采用该类重写的排序方法进行排序
                dataSource1.sorted().forEach(System.out::println);
                // 自定义排序规则
        //        dataSource1.sorted((s1, s2) -> s2.getScore() - s1.getScore()).forEach(System.out::println);
            }
        
            @Test
            public void limitAndSkipUsage() {
                Stream<Student> dataSource1 = getDataSource1();
                dataSource1.sorted((s1,s2)->s2.score-s1.score).limit(5).skip(2).forEach(System.out::println);
            }
        
            @Test
            public void mapUsage() {
                // 将流中的student对象,映射成对象的name
                Stream<Student> dataSource1 = getDataSource1();
                dataSource1.map(Student::getName).forEach(System.out::println);
            }
        
            /**
             * 需求:统计字符串中出现的所有字符
             */
            @Test
            public void flatMapUsage(){
                String [] arr1 = {"zhangsan","lisi"};
                // 流经过map之后,变成一个容器,此时可用扁平化映射
                Arrays.stream(arr1).map(x->x.split("")).flatMap(Arrays::stream).distinct().forEach(System.out::print);
            }
        }

         

 

 

 

参考:

  1. https://www.jianshu.com/p/3dc56886c2eb
  2. https://www.jianshu.com/p/7eaa0969b424
posted @ 2021-02-19 22:42  杰然不同2019  阅读(74)  评论(0编辑  收藏  举报