StreamAPI

作者: 椰子奶糖 | 来源:发表于2019-08-03 15:20 被阅读5次

    StreamAPI的作用

    • Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API(java.util.stream.*)。Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

    **注意: **
    ①Stream 自己不会存储元素。
    ②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
    ③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

    StreamAPI 的执行过程

    StreamAPI 的执行过程.png

    一、创建流

     @Test
        public void test1() {
        
            //可以通过Collection 系列集合提供stream 或parallelStream
            List<String> list = new ArrayList<>();
            Stream<String> stream1 = list.stream();
            
            //可以通过数组
            Integer[] nums = new Integer[10];
            Stream<Integer> stream2 = Arrays.stream(nums);
            
            //可以通过Stream类中静态方法
            Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5);
            
            //创建无限流
            //迭代
            //limit取前十个
            Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2).limit(10);
            stream4.forEach(System.out::println);
            
            //生成随机数(两个)
            Stream<Double> Stream5 = Stream.generate(Math::random).limit(2);
            Stream5.forEach(System.out::println);
        }
    

    二、中间操作

    筛选与切片:
    filter——接收 Lambda , 从流中排除某些元素。
    limit——截断流,使其元素不超过给定数量。
    skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
    distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素

    • filter:过滤某些元素
        @Test
        public void test2(){
            //所有的中间操作不会做任何的处理
            Stream<Employee> stream = emps.stream()
                    .filter((e) -> {
                        System.out.println("测试中间操作");
                        return e.getAge() <= 35;
                    });
    
            //只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”、“延迟加载”
            stream.forEach(System.out::println);
        }
    

    结果是:只留下年龄<=35的员工


    image.png
     @Test
        public void test2(){
            //所有的中间操作不会做任何的处理
            Stream<Employee> stream = emps.stream()
                    .filter((e) -> {
                        return e.getAge() <= 35;
    
                    }).limit(3);
    
            //只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”、“延迟加载”
            stream.forEach(System.out::println);
        }
    
    • 结果是:只留下前三个元素
    image.png
    • skip:跳过元素
     @Test
        public void test5(){
            emps.parallelStream()
                    .filter((e) -> e.getSalary() >= 5000)
                    .skip(2)
                    .forEach(System.out::println);
        }
    

    结果是:跳过了前两个


    image.png
    • distinct:去重
     @Test
        public void test6(){
            emps.stream()
                    .distinct()
                    .forEach(System.out::println);
        }
    

    结果是:将重复的赵六全部去除了[图片上传中...(映射中的Map.png-d90df4-1564816615552-0)]

    image.png

    映射:
    map——接收 Lambda , 将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
    flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

    • map与flatMap:


      映射中的Map.png
      flatMap.png
    @Test
        public void test21(){
            
            List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
    
    
           
           //map得到,的是一个新流,流中是流流里面是Character
            Stream<Stream<Character>> stream2 = strList.stream()
                    .map(StreamAPITest::filterCharacter);
            
            stream2.forEach((sm) -> {
                sm.forEach(System.out::println);
            });
            
            System.out.println("---------------------------------------------");
            //flatMap:将所有流连接成一个流
            Stream<Character> stream3 = strList.stream()
                    .flatMap(StreamAPITest::filterCharacter);
            stream3.forEach(System.out::println);
        } 
        
        
        public static Stream<Character> filterCharacter(String str){
            List<Character> list = new ArrayList<>();
            for (Character ch : str.toCharArray()) {
                list.add(ch);
            }
            return list.stream();
        }
    

    结果是:效果相同但是,但是遍历逻辑有所不同

    image.png

    排序:
    sorted()——自然排序
    sorted(Comparator com)——定制排序

     @Test
        public void test22(){
            emps.stream()
                    .map(Employee::getName)
                    .sorted()
                    .distinct()
                    .forEach(System.out::println);
            System.out.println("------------------------------------");
            emps.stream()
                    .sorted((x, y) -> {
                        if(x.getAge() == y.getAge()){
                            return x.getName().compareTo(y.getName());
                        }else{
                            return Integer.compare(x.getAge(), y.getAge());
                        }
                    }).distinct()
                    .forEach(System.out::println);
        }
    

    终止操作

    查找与匹配:
    allMatch--检查是否匹配所有元素
    anyMatch--检查是否至少匹配一个元素
    noneMatch--检查是否没有匹配所有元素
    findFirst--返回第一个元素
    findAny--返回当前流中的任意元素

    • 测试:
      @Test
        public void test01() {
            //检查是否所有员工状态都是BUSY
            boolean b1 = emps.stream()
                    .allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
            System.out.println(b1);
            //检查是否至少有一个员工状态都是BUSY
            boolean b2 = emps.stream()
                    .anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
            System.out.println(b2);
            //检查是否没有员工状态都是BUSY
            boolean b3 = emps.stream()
                    .noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
            System.out.println(b3);
    
            System.out.println("---------------------------------------------");
    
            //从大到小排序,取第一个(相当于Max)
            Optional<Employee> first = emps.stream()
                    .sorted((e1, e2) -> -Double.compare(e1.getSalary(), e2.getSalary()))
                    .findFirst();
            System.out.println(first.get());
    
            System.out.println("---------------------------------------------");
    
    
            //串行流,一个一个查,顺序不变,一般是拿的第一个
            Optional<Employee> any = emps.stream()
                    .filter((e1) -> e1.getStatus().equals(Employee.Status.FREE))
                    .findAny();
            System.out.println(any.get());
    
            System.out.println("---------------------------------------------");
    
            //并行流,多线程一起查,随机拿符合条件的
            Optional<Employee> any2 = emps.parallelStream()
                    .filter((e1) -> e1.getStatus().equals(Employee.Status.FREE))
                    .findAny();
            System.out.println(any2.get());
        }
    

    结果是:

    image.png
    • 这里需要注意的是,最后两个,单线程和多线程的区别,串行查出来的数据一般是按顺序的,并行就不一定了(赵六顺序再张三后面)

    查找与匹配:
    count--返回流中元素的总个数
    max--返回流中最大值
    min--返回流中最小值

     @Test
        public void test02() {
           //计数,员工人数
            long count = emps.stream()
                    .count();
            System.out.println(count);
    
            //按工资取出最大值员工
            Optional<Employee> max = emps.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
            System.out.println(max.get());
            
            //用map取出工资,再用min得到最小工资
            Optional<Double> min = emps.stream()
                    .map(Employee::getSalary)
                    .min(Double::compare);
            System.out.println(min.get());
        }
    

    运行结果:

    image.png

    归约:
    reduce(T identity, BinaryOperator) / reduce(BinaryOperator)
    ——可以将流中元素反复结合起来,得到一个值。

    @Test
        public void test1() {
            List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    
            //计算和
            //计算结果作为x,再从数组中取出新值作为y,进行下一步计算
            Integer sum = list.stream()
                    .reduce(0, (x, y) -> x + y);
            
            System.out.println(sum);
    
            System.out.println("----------------------------------------");
           
           //计算总工资
            Optional<Double> op = emps.stream()
                    .map(Employee::getSalary)
                    .reduce(Double::sum);
    
            System.out.println(op.get());
        }
    
    

    结果是:

    image.png

    collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法

     @Test
        public void test3() {
            //取名字,封装成list
            List<String> list = emps.stream()
                    .map(Employee::getName)
                    .collect(Collectors.toList());
    
            list.forEach(System.out::println);
    
            System.out.println("----------------------------------");
        
           //取名字,封装成set
            Set<String> set = emps.stream()
                    .map(Employee::getName)
                    .collect(Collectors.toSet());
    
            set.forEach(System.out::println);
    
            System.out.println("----------------------------------");
            
            //取名字,封装成hashset
            HashSet<String> hs = emps.stream()
                    .map(Employee::getName)
                    .collect(Collectors.toCollection(HashSet::new));
    
            hs.forEach(System.out::println);
        }
    

    结果是:按照各种集合的规则将流封装成各种集合


    image.png
    collect是基于Collectors实现的,而Collectors除了上面的to....之外还有

    maxBy:最大
    minBy:最小
    summingDouble:求和
    averagingDouble:平均值
    counting:计数
    summarizingDouble:统计,上面5种都包括
    groupingBy:分组(可以自定义分组,可以多级分组)
    partitioningBy:分区,将满足条件的分成一个区,不满足的分成一个区
    joining:连接字符串,delimiter:分割符,prefix:前缀,suffix:后缀
    reducing:归约

    相关文章

      网友评论

        本文标题:StreamAPI

        本文链接:https://www.haomeiwen.com/subject/bmmjdctx.html