• Java 8 新特性 Stream API 介绍与使用


    Stream 介绍

    Java8中有两大最为重要的改变。

    第一个是 Lambda表达式;另外一个则是 Stream API (java.util.stream.*)。

    Stream是 Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。

    使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简而言之,Stream API提供了一种高效且易于使用的处理数据的方式。

    流(Stream)到底是什么?

    是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
    “集合讲的是数据,流讲的是计算!”

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

    Stream 的操作三个步骤

    ● 创建Stream

    一个数据源(如集合、数组),获取一个流

    ● 中间操作

    一个中间操作链,对数据源的数据进行处理,

    ● 终止操作

    一个终止操作,执行中间操作链,并产生结果

    创建 Stream

    Java8 中的Collection接口被扩展,提供了两个获取流的方法:

    ● default Stream stream() :返回一个顺序流

    ● default Stream parallelStream() :返回一个并行流

      //1,可以通过 Collection 系列集合提供的 stream() 或者 parallelStream()
            List<String> list = new ArrayList<>();
            Stream<String> stream1 = list.stream();
    
    • 1
    • 2
    • 3

    由数组创建流

    Java8 中的Arrays 的静态方法stream()可以获取数组流:

    ● staticStreamstream(T[] array):返回一个流

     //2.通过 Arrays 中的静态方法 stream() 获取数组流
     Employee[] emps = new Employee[10];
     Stream<Employee> stream2 = Arrays.stream(emps);
    
    • 1
    • 2
    • 3

    重载形式,能够处理对应基本类型的数组:

    public static IntStream stream(int[] array)

    public static LongStream stream(long[] array)

    public static DoubleStream stream(double[] array)

    由值创建流

    可以使用静态方法Stream. of(),通过显示值创建一个流。它可以接收任意数量的参数。

    public staticStreamof(T… . values) :返回一个流

       //3.通过 Stream 类中的静态方法 of()
       Stream<String> stream3 = Stream.of("aa", "bb", "cc");
    
    • 1
    • 2

    由函数创建流:创建无限流

    可以使用静态方法Stream.iterate()和Stream. generate(),创建无限流。

    ● 迭代
    public staticStream iterate(final T seed,finalUnaryOperator f)

    ● 生成
    public staticStreamgenerate (Supplier s) :

      //4.创建无限流
            //迭代
            Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
            stream4.limit(10).forEach(System.out::println);
            //生成
            Stream.generate(() -> Math.random())
                    .limit(5)
                    .forEach(System.out::println);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Stream 的中间操作

    多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。

    筛选与切片

    ● filter() 使用

       @Test
        public void test1() {
            //内部迭代:迭代操作由Stream API完成
            //中间操作:不会执行任何操作
            Stream<Employee> stream = employees.stream()
                    .filter((e -> {
                        return e.getAge() > 35;
                    }));
            //中间操作:一次性执行全部内容,即“惰性求值”
            stream.forEach(System.out::println);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    ● limit() 使用

       @Test
        public void test3() {
            employees.stream()
                    .filter((e) -> e.getSalary() > 5000)
                    .limit(2)
                    .forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ● skip()、distinct() 使用

      @Test
        public void test4() {
            employees.stream()
                    .filter((e) -> e.getSalary() > 5000)
                    .skip(2)
                    .distinct()
                    .forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    映射

    ● map()、flatMap() 使用

        @Test
        public void test5() {
            List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
            list.stream()
                    .map((str) -> str.toUpperCase())
                    .forEach(System.out::println);
            System.out.println("----------------------");
            employees.stream()
                    .map(Employee::getName)
                    .forEach(System.out::println);
            System.out.println("----------------------");
    //        Stream> stream = list.stream()
    //                .map(TestStreamAPI2::filterCharacter);
    //        stream
    //                .forEach((sm) -> {
    //                    sm.forEach(System.out::println);
    //                });
    
            System.out.println("----------------------");
            Stream<Character> sm = list.stream()
                    .flatMap(TestStreamAPI2::filterCharacter);
            sm.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    排序

    ● sorted() 使用

     @Test
        public void test6() {
            List<String> list = Arrays.asList("ccc", "aaa", "bbb", "ddd", "eee");
            list.stream()
                    .sorted()
                    .forEach(System.out::println);
            System.out.println("----------------------");
            employees.stream()
                    .sorted((e1, e2) -> {
                        if (e1.getAge().equals(e2.getAge())) {
                            return e1.getName().compareTo(e2.getName());
                        } else {
                            return -e1.getAge().compareTo(e2.getAge());
                        }
                    }).forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Stream 的终止操作

    终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。

    查找与匹配

    ● allMatch()、anyMatch()、findFirst()…使用

        @Test
        public void test2() {
            long count = employees.stream()
                    .count();
            System.out.println(count);
    
            Optional<Employee1> op1 = employees.stream()
                    .max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
            System.out.println(op1.get());
    
            Optional<Double> min = employees.stream()
                    .map(Employee1::getSalary)
                    .min(Double::compare);
            System.out.println(min);
        }
    
        @Test
        public void test1() {
            boolean b = employees.stream()
                    .allMatch((e) -> e.getStatus().equals(Employee1.Status.Busy));
            System.out.println(b);
            System.out.println("------------------");
            boolean b1 = employees.stream()
                    .anyMatch((e) -> e.getStatus().equals(Employee1.Status.Busy));
            System.out.println(b1);
    
            boolean b3 = employees.stream()
                    .noneMatch((e) -> e.getStatus().equals(Employee1.Status.Busy));
            System.out.println(b3);
            Optional<Employee1> op = employees.stream()
                    .sorted((e1, e2) -> -Double.compare(e1.getSalary(), e2.getSalary()))
                    .findFirst();
            System.out.println(op.get());
    
            Optional<Employee1> op2 = employees.stream()
                    .filter(e -> e.getStatus().equals(Employee1.Status.Free))
                    .findAny();
            System.out.println(op2.get());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    归约

    备注:map 和 reduce 的连接通常称为map-reduce 模式,因 Google 用它
    来进行网络搜索而出名。

    ● map()、reduce() 使用

      @Test
        public void test3() {
            List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
            Integer sum = list.stream()
                    .reduce(0, (x, y) -> x + y);
            System.out.println(sum);
    
            Optional<Double> op = employees.stream()
                    .map(Employee1::getSalary)
                    .reduce(Double::sum);
            System.out.println(op.get());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    收集

    Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

    ● toList()、maxBy()、partitioningBy()… 使用

        @Test
        public void test10() {
            String str = employees.stream()
                    .map(Employee1::getName)
                    .collect(Collectors.joining());
            System.out.println(str);
        }
    
        @Test
        public void test9() {
            DoubleSummaryStatistics ds = employees.stream()
                    .collect(Collectors.summarizingDouble(Employee1::getSalary));
            System.out.println(ds.getAverage());
            System.out.println(ds.getMax());
            System.out.println(ds.getCount());
        }
    
        //分区
        @Test
        public void test8() {
            Map<Boolean, List<Employee1>> pb = employees.stream()
                    .collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000));
            System.out.println(pb);
        }
    
        //多级分组
        @Test
        public void test7() {
            Map<Employee1.Status, Map<String, List<Employee1>>> map = employees.stream()
                    .collect(Collectors.groupingBy(Employee1::getStatus, Collectors.groupingBy((e) -> {
                        if (e.getAge() <= 35) {
                            return "青年";
                        } else if (e.getAge() <= 50) {
                            return "中年";
                        } else {
                            return "老年";
                        }
                    })));
            Set<Map.Entry<Employee1.Status, Map<String, List<Employee1>>>> entries = map.entrySet();
            for (Map.Entry<Employee1.Status, Map<String, List<Employee1>>> entry : entries) {
                System.out.println(entry.getValue());
            }
        }
    
        //分组
        @Test
        public void test6() {
            Map<Employee1.Status, List<Employee1>> map = employees.stream()
                    .collect(Collectors.groupingBy(Employee1::getStatus));
            Set<Map.Entry<Employee1.Status, List<Employee1>>> entrySet = map.entrySet();
            for (Map.Entry<Employee1.Status, List<Employee1>> statusListEntry : entrySet) {
                System.out.println(statusListEntry.getValue());
            }
        }
    
        @Test
        public void test5() {
            //总数
            Long count = employees.stream()
                    .collect(Collectors.counting());
            System.out.println(count);
            System.out.println("-------------------");
            //平均值
            Double avg = employees.stream()
                    .collect(Collectors.averagingDouble(Employee1::getSalary));
            System.out.println(avg);
            //总和
            Double sum = employees.stream()
                    .collect(Collectors.summingDouble(Employee1::getSalary));
            System.out.println(sum);
            //最大值
            Optional<Employee1> max = employees.stream()
                    .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
            System.out.println(max.get());
            //最小值
    //        Optional min = employees.stream()
    //                .collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
    //        System.out.println(min.get());
            Optional<Double> min = employees.stream()
                    .map(Employee1::getSalary)
                    .collect(Collectors.minBy(Double::compare));
            System.out.println(min.get());
        }
    
        @Test
        public void test4() {
            List<String> list = employees.stream()
                    .map(Employee1::getName)
                    .collect(Collectors.toList());
            list.forEach(System.out::println);
    
            System.out.println("-----------------");
            Set<String> list2 = employees.stream()
                    .map(Employee1::getName)
                    .collect(Collectors.toSet());
            list2.forEach(System.out::println);
    
            HashSet<String> hs = employees.stream()
                    .map(Employee1::getName)
                    .collect(Collectors.toCollection(HashSet::new));
            hs.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102

    感谢参与

    https://www.bilibili.com/video/BV1ut411g7E9?p=7

  • 相关阅读:
    无用小程序之——论如何利用python的pyautogui和特别喜欢发“嗯”*n的人实现部分自动化QQ聊天
    pwn学习(3)BUUCTF-rip
    Android SELinux 参数语法介绍及基础分析
    状态管理容器Pinia
    【Java成王之路】EE初阶第十四篇:(网络原理) 4
    从十月稻田,看大米为何能卖出200亿市值?
    结合Command以AOP方式实现事务
    js-22同源策略
    springMVC第一天
    递归是会更秀strtok
  • 原文地址:https://blog.csdn.net/weixin_46665411/article/details/126354471