• Java 8 新特性 Ⅲ


    EmployeeData.java (下面需要用到的数据)

    public class EmployeeData {
       public static List<Employee> getEmployees(){ // 返回list集合
           List<Employee> list = new ArrayList<>(); // 创建数组
           list.add(new Employee(19, 1000.0,1,"sam"));
           list.add(new Employee(18, 2000.0,2,"Tom"));
           list.add(new Employee(29, 54000.0,3,"Tonny"));
           list.add(new Employee(20, 100032.0,4,"sammy"));
           list.add(new Employee(39, 12100.0,5,"Sunny"));return list;
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Steam API

    • Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。极大的提高效率

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

      使用 Stream API对集合数据进行操作, 就类似于使用SQL执行的数据库查询 (Stream API 可以处理如redis等非关系型数据库的数据)

    什么是 Stream

    Stream 是数据渠道, 用于操作数据源(集合、数组等)所生产的元素序列

    Stream与Collection集合的区别: Collection 是一种静态的内存数据结构, 讲的是数据 (面向内存, 存储在内存中); 而Stream是有关计算的, 讲的是计算, 面向CPU, 通过CPU实现计算。

    简而言之, Stream API

    注:

    • Stream 自身不会存储数据
    • Stream 不会改变源对象, 会返回一个持有结果的新Stream
    • Stream 操作是延迟执行的, 会等到需要结果时才执行. 一旦执行终止操作, 就会停止
    • Stream 一旦执行了终止操作, 就不能调用其他中间操作or终止操作了

    执行流程

    • Stream 的实例化
    • 一系列中间操作
    • 执行终止操作
    步骤一 Stream 实例化
    1. 通过集合创建 Stream
    // 创建 Stream方法一: 通过集合
    @Test
    public void test1(){
        List<Employee> list = EmployeeData.getEmployees();
        // 集合. 就能看到有stream方法可以调用
        // default Stream stream() : 返回一个顺序流
        Stream<Employee> stream = list.stream();
        // default Stream parallelStream() : 返回一个并行流
        Stream<Employee> stream1 = list.parallelStream();
        System.out.println(stream);
        System.out.println("===============");
        System.out.println(stream1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    运行效果: (输出的是Stream对象)

    Stream对象

    1. 通过数组来创建 Stream
    // 创建 Stream方法二: 通过数据
    @Test
    public void test2(){
        // 调用Arrays类的 static Stream stream(T[] array)
        Integer[] arr = new Integer[]{1,2,3,1,1,4};
        Stream<Integer> stream = Arrays.stream(arr); // 可以清楚看到处理的数据类型 Integer, Stream 不存储元素
        System.out.println(stream);
        System.out.println("=======================");
        int[] arr1 = new int[]{1,2,31,21,1};
        IntStream stream1 = Arrays.stream(arr1); // 具体指明操作什么类型的数据(看传的是什么数据) 有 IntStream, DoubleStream ...
        System.out.println(stream1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    运行效果:

    程序输出

    1. 使用 stream的 of() 方法来创建
    // 创建 Stream方法三: 通过Stream的of()
    @Test
    public void test3(){
        Stream<String> stream = Stream.of("aa", "bb", "AA", "CC");
        System.out.println(stream);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    运行效果:

    输出效果

    步骤二 中间操作

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    常见的中间操作

    多个中间操作可以连接起来形成一个流水线, 除非流水线上触发终止操作, 否则中间操作不会执行任何的处理, 而是在终止操作一次性全部处理

    1. 筛选与切片

    筛选与切片

    // 1. 筛选与切片
    @Test
    public void test1(){
        // filter() 接受lambda, 从流中排除某些元素 (支持多条件 用 && || 连接)
        // 查询员工表中薪资大于 7000的员工信息
        List<Employee> list = EmployeeData.getEmployees();
        Stream<Employee> stream = list.stream();
        stream.filter(emp -> emp.getSalary() > 7000).forEach(System.out::println); // forEach() 相当于一个终止条件(不然不会执行该语句&输出)
        System.out.println();// limit(n), 截断流, 使元素
    //        stream.limit(2).forEach(System.out :: println); // 这种做法是错误的, 因为上面的stream已经执行终止操作
        // 所以不能调用其他中间操作or终止操作, 只能新造一个
        list.stream().limit(4).forEach(System.out :: println); // 限制输出 前几个数据 (可以连续操作)
        System.out.println();
        // skip(n) 跳过元素, 返回一个除前n个元素的流; 若流中元素不足n个, 则会返回一个空流
        list.stream().skip(2).forEach(System.out :: println);
        System.out.println();
        // distinct() 去重, 通过流生成元素的 hashCode() 和 equals() 去除重复元素 (在Employee.java 里改写了)
        // 原有的方法会认为下面几条数据是一致的
        list.add(new Employee(18, 2000.0,2,"sam"));
        list.add(new Employee(18, 2000.0,2,"sam"));
        list.add(new Employee(18, 2000.0,2,"sam"));
    ​
        list.stream().distinct().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

    执行效果:

    执行效果

    映射

    // 2 映射
    @Test
    public void test2(){
        // map(Function f) - 接受一个函数作为参数. 将元素转换成其他形式or提取信息
        // 小写 -> 大写
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
        list.stream().map(str -> str.toUpperCase()).forEach(System.out :: println);
        // map 里 也可以写成 str :: toUpperCase
        System.out.println();
        // 获取 员工姓名长于3的员工
        List<Employee> employees = EmployeeData.getEmployees();
        employees.stream().filter(emp -> emp.getName().length() > 3).forEach(System.out :: println);
        System.out.println();
        // 获取 员工姓名长度大于3的员工姓名
        employees.stream().filter(emp -> emp.getName().length() > 3).map(emp -> emp.getName()).forEach(System.out :: println);
        // 先过滤后映射
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    执行效果:

    执行效果

    stream流

    排序

    // 3 排序
    @Test
    public void test3(){
        Integer[] arr = new Integer[]{32,3213,1231,123};
        String[] arr1 = new String[]{"GG", "DD", "MM", "SS", "JJ"};
        // sorted() 自然排序 (默认升序排序)
        Arrays.stream(arr).sorted().forEach(System.out :: println);
        System.out.println(Arrays.toString(arr)); // 是原来本身, stream流并不会改变容器本身
        List<Employee> list = EmployeeData.getEmployees();
    //        list.stream().sorted().forEach(System.out :: println); // 因为Employee没有实现Comparable接口, 所以会报错
    //        报错: java.lang.ClassCastException: java8.data.Employee cannot be cast to java.lang.Comparable
        // sorted(Comparator com) 定制排序 (lambda表达式 返回的bool值)
        list.stream().sorted((e1, e2) -> e1.getAge() -e2.getAge()).forEach(System.out::println);// 升序
        System.out.println();
        Arrays.stream(arr1).sorted((s1, s2) -> -s1.compareTo(s2)).forEach(System.out :: println); // 降序排列(-, 默认升序)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    执行效果:

    执行效果

    对数据操作的例子

    // 匹配和查找
    @Test
    public void test1(){
        // allMatch(Predicate p) - 检查是否匹配所有元素 Predicate 里面的方法为 boolean test(T t);
        // 是否所有的员工的年龄都大于18
        List<Employee> list = EmployeeData.getEmployees();
        System.out.println(list.stream().allMatch(emp -> emp.getAge() > 18)); // false
        // anyMatch(Predicate p)
        // 是否存在员工年龄大于18 (存在一个就返回true)
        System.out.println(list.stream().anyMatch(emp -> emp.getAge() > 18)); // true
        // findFirst 返回第一个元素 返回的是Optional
        System.out.println(list.stream().findFirst().get()); // .get() 返回第一个参数
    }// 统计数字特征
    @Test
    public void test2() {
        // count 返回流元素的总个数
        // 统计工资超过 7000元 员工个数
        List<Employee> list = EmployeeData.getEmployees();
        System.out.println(list.stream().filter(emp -> emp.getSalary() > 7000).count());
        // max() 返回流中的最大值
        // 返回最高工资的钱数 map 取其中的内容(列)
        // 要先map 然后 max 因为 max 是一个终止操作
        System.out.println(list.stream().map(emp->emp.getSalary()).max((e1, e2)-> Double.compare(e1, e2)).get()); // .get() 是取出Optional中的元
        // min() 同理
        // forEach(Customer c) 内部迭代
        list.stream().forEach(System.out :: println); // 相当于将方法作为参数传入 accpt 函数中、// 针对于集合, jdk8 新增了一个遍历的方法
        list.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

    执行结果(test1()):

    输出结果

    test2():

    输出结果

    1. 规约

    规约

    // 规约
    @Test
    public void test3(){
        // reduce(T identity, BinaryOperator) 将流中的元素 反复结合起来
        // 计算1-10自然数的和
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        System.out.println(list.stream().reduce(0, (x1, x2) -> x1 + x2)); // 第一个参数为初始种子
        // reduce(BinaryOperator) 返回 Optional
        List<Employee> employees = EmployeeData.getEmployees();
        System.out.println(employees.stream().map(emp -> emp.getSalary()).reduce((s1, s2) -> Double.sum(s1, s2))); // 可以在最后用 .get() 取出Optional里的值
        // 当然上面lambda表达式中可以替换为 Double::sum
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    执行结果:

    输出结果

    1. 收集

    收集

    Collector接口中方法的实现决定了如何对流执行收集的操作(如: 收集到 List, Set, Map …)

    toList, toSet, toCollection, counting 统计流中元素数量 等… 功能

    // 收集 (把结果放回原处)
    @Test
    public void test4() {
        // collect() 将流转换成其他形式
        List<Employee> list = EmployeeData.getEmployees();
        // 查找工资大于6000的员工, 结果返回一个List或Set Collectors.tolist() / Collectors.toset()
        List<Employee> list1 = list.stream().filter(emp -> emp.getSalary() > 6000).collect(Collectors.toList());
        list1.forEach(System.out :: println); // 这里的list1 已经是处理好之后的数据了, 然后 forEach是遍历列表, 打印
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    执行结果:

    输出结果

    步骤三 终止查询

    .max() .min() .forEach() … 等为最后对数据的终止条件, 此时 stream流就不能继续使用了, 需要用的话 需要重新创建 ~

  • 相关阅读:
    Vue解构工作原理
    动态住宅代理VS静态住宅代理,怎么选择?
    服务器日志出现大量NTLM(NT LAN Manager)攻击
    内存及换算
    五、Express
    【LeetCode】刷题模版/套路合集(持续更新)
    支付宝支持给微信好友转账?
    PysparkNote103---window滑窗
    记录前后端接口使用AES+RSA混合加解密
    LINUX之ftp服务-2
  • 原文地址:https://blog.csdn.net/weixin_46388660/article/details/134016369