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

    1.流的基本概念 1.1 什么是流? 流是Java8引入的全新概念,它用来处理集合中的数据,暂且可以把它理解为一种...

  • StreamAPI

    StreamAPI的作用 Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stre...

  • StreamAPI

  • Flink Dag简述

    Flink Dag 1、流程简图 2、流程简述 ① API : StreamAPI: 实时流 API BatchA...

  • StreamAPI的并行

    由于上次对于并行流与串行流的学习忘记记录,于是这篇补上 上一篇:https://www.jianshu.com/p...

  • 强大的StreamAPI

    04 强大的StreamAPI 什么是Stream流: 对于数据源,可以是Collection或是Array,进行...

  • 写给大忙人的javaSE8(2)-常用流操作

    java8中的 StreamAPI 非常丰富,本文介绍几种比较重要的API。 collect(toList()) ...

  • through2

    帮忙处理stream的,因为Node自带的streamAPI不好用,相当于新建(封装)一个流(不需要每次newSt...

  • Java8之StreamAPI

    Java8的两大特性(1)Lambda 表达式Lambda表达式 前面文章已经详细讲解过 lambda语法、函数式...

  • 常用的Stream API

    中间操作:返回一个新的stream 终端操作:结束并返回结果 举个使用StreamAPI的例子:从一个唱片集alb...

网友评论

    本文标题:StreamAPI

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