JDK8——streamAPI学习笔记

    科技2022-07-10  100

    一、 流的概念

    1、什么是流(stream)

           在Java 8 中,stream是新增的一大亮点,Stream 是对集合对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作,或者大批量数据操作。它像是一种是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列,流本身不是一种数据结构,不能够存储数据,它只关注于数据内部的计算,在一定程度上类似于迭代器,单向运行,只能使用一次,但是与之不同的是Stream能够并行化操作。简单来说:集合专注于数据,而流专注于计算

    2、Stream的操作步骤

    (1)、创建Stream

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

    (2)、中间操作

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

    (3)、终止操作

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

    二、创建Stream

    创建Stream的方式有多种

    1、collection接口提供

     default Stream<E> stream() : 返回一个顺序流 

     default Stream<E> parallelStream() : 返回一个并行流

    List<String> list = new ArrayList<>(); Stream<String> stream = list.stream(); //获取一个顺序流 Stream<String> parallelStream = list.parallelStream(); //获取一个并行流

    2、通过Arrays中的静态方法stream()获取数组流

    static <T> Stream<T> stream(T[] array)

    Integer[] nums = new Integer[10]; Stream<Integer> stream1 = Arrays.stream(nums);

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

    public static<T> Stream<T> of(T... values) 

    Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);

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

    迭代 public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)  生成 public static<T> Stream<T> generate(Supplier<T> s) 

    //迭代,生成偶数集合无限流 Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2) //生成随机数 Stream<Double> stream4 = Stream.generate(Math::random);

    三、中间操作

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

    1筛选与切片

    class Employee { private int id; private String name; private int age; private double salary; } List<Employee> emps=Arrays.asList(...); System.out.println("输出年龄大于30的员工"); emps.stream().filter(e->e.getAge()>30) .forEach(System.out::println); System.out.println("去重输出");//内部需要重写hashcode和equals方法 emps.stream().distinct() .forEach(System.out::println); System.out.println("跳过前两个元素"); emps.stream().skip(2) .forEach(System.out::println); System.out.println("限制输出前4位员工"); emps.stream() .limit(4) .forEach(System.out::println);

    2、映射

    System.out.println("得到每一个员工的姓名:"); emps.stream() .map(e->e.getName()) .forEach(System.out::println); System.out.println("Map输出每一位员工名字每一个字"); emps.stream() .map(e -> e.getName()) .map(Main::getCh) .forEach(em->{ em.forEach(ems-> System.out.println(ems)); }); System.out.println("flatMao输出每一位员工名字每一个字"); emps.stream() .map(e -> e.getName()) .flatMap(Main::getCh) .forEach(System.out::println);

    3、排序

    //自然排序需要对象实现Comparable接口 emps.stream().sorted() .forEach(System.out::println); emps.stream().sorted((x,y)->Double.compare(x.getSalary(),y.getSalary())) .forEach(System.out::println);

    四、终止操作

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

    流进行了终止操作后,不能再次使用

    1、查找与匹配

    boolean b = emps.stream() .allMatch(e -> e.getAge() > 30); System.out.println("所有员工年龄是否大于30->"+b); long count = emps.stream().count(); System.out.println("员工数量:"+count); Optional<Employee> max = emps.stream(). max((x, y) -> Integer.compare(x.getAge(), y.getAge())); System.out.println("年龄最大的员工:"+max);

    2、归约

    Double reduce = emps.stream() .map(Employee::getSalary) .reduce(0.0, (x, y) -> x + y); System.out.println("所有员工的总工资为:"+reduce); //返回参数为Optional的,因为初始参数未赋值,防止空指针 Optional<Double> salary = emps.stream() .map(Employee::getSalary) .reduce(Double::sum); System.out.println("所有员工的总工资为:"+salary);

    3、收集

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

    List<Integer> list = emps.stream() .map(Employee::getAge) .collect(Collectors.toList()); list.forEach(e-> System.out.println(e)); Set<Integer> set = emps.stream() .map(Employee::getAge) .collect(Collectors.toSet()); set.forEach(e-> System.out.println(e)); HashSet<Integer> map = emps.stream() .map(Employee::getAge) .collect(Collectors.toCollection(HashSet::new)); map.forEach(e-> System.out.println(e)); Optional<Double> max = emps.stream() .map(Employee::getSalary) .collect(Collectors.maxBy(Double::compare)); System.out.println("员工工资最高:"+max.get()); Optional<Employee> op = emps.stream() .collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))); System.out.println("员工工资最低:"+op.get()); Map<String, List<Employee>> name = emps.stream().collect(Collectors.groupingBy(e -> e.getName())); System.out.println("按名分组"+name); Map<String, Map<Double, List<Employee>>> names = emps.stream(). collect(Collectors.groupingBy(e -> e.getName(), Collectors.groupingBy(f -> f.getSalary()))); System.out.println("多级分组,先按名,再按工资"+names); Map<Boolean, List<Employee>> collect = emps.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > 7000)); System.out.println("分区:"+collect);

    五、结论

    Stream自己不会存储元素。Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。所有 Stream 的操作必须以 lambda 表达式为参数不支持索引访问集合有固定大小,Stream 则不必当一个 Stream 是并行化的,就不需要再写多线程代码,所有对它的操作会自动并行进行的。

     

    Processed: 0.038, SQL: 8