强大的StreamAPI

作者: 随手点灯 | 来源:发表于2020-04-12 11:47 被阅读0次

04 强大的StreamAPI

什么是Stream流:

对于数据源,可以是Collection或是Array,进行一系列的中间操作,然后转化成我们需要的数据.

进行中间操作的对象就是流,流不会改变原来的集合和数组.

数组和集合讲究的是数据,流讲的就是计算:

注意三点:

  1. Stream自己不存储元素
  2. Stream不会改变原来的UI想,相反,他们会返回一个持有结果的新Stream
  3. Stream的操作是延迟的,意味着他们等到需要结果的时候才会执行.

如何操作Stream呢?分为三步:

  1. 创建流 : 把一个数据源(Collection,Array)获取一个流

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

  3. 终止操作 : 执行中间操作链,并产生结果.

4.1 首先看看创建流:

       // 创建流
        // 1. 通过Collection的方法创建流
        List<String> strList = new ArrayList<>();
        Stream<String> listStream = strList.stream();

        // 2. 通过Arrays创建流
        Employee[] emps = new Employee[10];
        Stream<Employee> arrayStream = Arrays.stream(emps);

        // 3. 通过Stream的of创建流
        Stream<String> streamStream = Stream.of("aaa", "ddd");

        // 4. 无限流
        // 4.1 迭代
        Stream<Integer> iterate = Stream.iterate(0, (x) -> x + 2);
        iterate.limit(10).forEach(System.out::println);

        // 4.2 生成
        Stream<Integer> generate = Stream.generate(() -> new Random().nextInt(100));
        generate.limit(10).forEach(System.out::println);

4.2 筛选和切片

filter : 过滤
distinct : 去重
skip : 跳过
limit : 截断流

public class Test {
    public static void main(String[] args) {

        /**
         * 筛选与切片:
         * filter--接收Lambda,从流中排除某些元素
         * limit--截断流,使其元素不超过给定的数量
         * skip(n)--跳过元素,返回一个扔掉了前面n个元素的流,如果元素不超过n个,返回一个空流
         * distinct--筛选,通过流中元素的hashCode和equals去掉元素
         */

        Employee e1 = new Employee(1,"张三");
        Employee e2 = new Employee(2,"李四");
        Employee e3 = new Employee(3,"王五");
        Employee e4 = new Employee(3,"王五");

        List<Employee> lists = new ArrayList<>(3);
        lists.add(e1);
        lists.add(e2);
        lists.add(e3);
        lists.add(e4);

        lists.stream().filter(e -> e.getId() > 1)
                      .limit(3).skip(1).distinct()
                      .forEach(System.out::println);


    }

}

@Data
class Employee {
    private Integer id;
    private String name;

    public Employee() {
    }

    public Employee(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Employee(Integer id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return Objects.equals(id, employee.id) &&
                Objects.equals(name, employee.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}

4.3 映射

public class Test {
    public static void main(String[] args) {

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

        Employee e1 = new Employee(1,"张三");
        Employee e2 = new Employee(2,"李四");
        Employee e3 = new Employee(3,"王五");
        Employee e4 = new Employee(3,"王五");

        List<Employee> lists = new ArrayList<>(3);
        lists.add(e1);
        lists.add(e2);
        lists.add(e3);
        lists.add(e4);

        // 需求1 : 根据这个集合输出所有人的名字
        lists.stream().map( employee -> employee.getName())
                      .distinct()
                      .forEach(System.out::println);

        System.out.println("----------------------------------------");

        // 需求2 : 根据这个集合输出所有人名字的字符,flatMap是将输入的数据转换为一个流,并将这个流和其他流合并起来
        lists.stream().flatMap(employee -> {
            char[] chars = employee.getName().toCharArray();
            List<Character> characters = new ArrayList<>();
            for (char aChar : chars) {
                characters.add(aChar);
            }
            return characters.stream();
        }).distinct().forEach(System.out::println);




    }

}

@Data
class Employee {
    private Integer id;
    private String name;

    public Employee() {
    }

    public Employee(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Employee(Integer id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return Objects.equals(id, employee.id) &&
                Objects.equals(name, employee.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}

4.4 排序

public class Test {
    public static void main(String[] args) {

        /**
         * 排序:
         *      sorted() -- 自然排序
         *      sorted(Comparator com) -- 定制排序
         */

        List<String> strLists = new ArrayList<>();
        strLists.add("aa");
        strLists.add("vv");
        strLists.add("xx");
        strLists.add("33");

        strLists.stream().sorted().forEach(System.out::println);

        System.out.println("-------------------------");

        List<Employee> employeeList = new ArrayList<>();
        Employee e1 = new Employee(1, "张三");
        Employee e2 = new Employee(2, "李四");
        Employee e3 = new Employee(3, "王五");
        Employee e4 = new Employee(3, "王五");

        employeeList.add(e1);
        employeeList.add(e2);
        employeeList.add(e3);
        employeeList.add(e4);

        employeeList.stream().
                sorted((x, y) -> x.getName().hashCode() - y.getName().hashCode()).
                forEach(x -> System.out.println(x.getName()));


    }

}

@Data
class Employee {
    private Integer id;
    private String name;

    public Employee() {
    }

    public Employee(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Employee(Integer id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return Objects.equals(id, employee.id) &&
                Objects.equals(name, employee.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}

4.5 StreamAPI的终止操作--查找与匹配

  1. allMatch--检查是否匹配所有元素
  2. anyMatch--检查是否至少匹配一个元素
  3. noneMatch--检查是否没有匹配所有元素
  4. findFirst--返回第一个元素
  5. findAny--返回流中的任意元素
  6. count--返回元素个数
  7. max--返回流中最大值
  8. min--返回流中最小值
List<Employee> employeeList = new ArrayList<>();
        Employee e1 = new Employee(1, "张三");
        Employee e2 = new Employee(2, "李四");
        Employee e3 = new Employee(3, "王五");
        Employee e4 = new Employee(3, "王五");

        employeeList.add(e1);
        employeeList.add(e2);
        employeeList.add(e3);
        employeeList.add(e4);

        boolean b = employeeList.stream().allMatch(employee -> employee.getId() > 0);
        boolean c = employeeList.stream().anyMatch(employee -> employee.getName().equals("张三"));
        boolean d = employeeList.stream().noneMatch(employee -> employee.getName().equals("六大"));
        Optional<Employee> first = employeeList.stream().findFirst();
        Employee employee = first.get();
        Optional<Employee> any = employeeList.stream().findAny();
        Employee employee1 = any.get();
        long count = employeeList.stream().count();
        Optional<Employee> max = employeeList.stream().max((x, y) -> x.getName().length() - y.getName().length());
        Optional<Employee> min = employeeList.stream().min((x, y) -> x.getName().length() - y.getName().length());

4.6 归约和收集

归约 reduce(T identity,BinaryOperator) / reduce(BinaryOperator) 将流中的元素结合起来,得到一个值

        List<Employee> employeeList = new ArrayList<>();
        Employee e1 = new Employee(1, "张三");
        Employee e2 = new Employee(2, "李四");
        Employee e3 = new Employee(3, "王五");
        Employee e4 = new Employee(3, "王五");

        employeeList.add(e1);
        employeeList.add(e2);
        employeeList.add(e3);
        employeeList.add(e4);

        // 统计名字的个数

        Stream<Map<Character, Integer>> mapStream = employeeList.stream().flatMap(employee -> {
            Map<Character, Integer> hashMap = new HashMap<>();
            String name = employee.getName();
            char[] chars = name.toCharArray();
            for (char aChar : chars) {
                Integer integer = hashMap.get(aChar);
                if (integer == null) {
                    hashMap.put(aChar, 1);
                } else {
                    hashMap.put(aChar, integer + 1);
                }
            }
            return Stream.of(hashMap);

        });
        
        Optional<Map<Character, Integer>> reduce = mapStream.reduce((x, y) -> {
                    Map<Character, Integer> result = new HashMap<>();
                    x.keySet().forEach( z -> {
                        result.put(z,x.get(z));
                    });

                    y.keySet().forEach( v -> {
                        if (result.get(v) != null) {
                            result.put(v,result.get(v) + 1);
                        }else {
                            result.put(v,y.get(v));
                        }
                    });

                    return result;
                }
        );

        Map<Character, Integer> characterIntegerMap = reduce.get();
        System.out.println(characterIntegerMap);
    }

}

收集: collect--将流转换为其他形式,接收一个Collect接口来实现,用于Stream中元素汇总

       /**
            收集: collect(Collector c) 将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总方法
            toList: 把流元素收集到List
            toSet:
            toCollection:
            counting
            summingInt
            averageingInt
            summarizingInt: 收集流中Integer属性的值,比如平均值
            joining: 连接流中的字符串
            maxBy : 根据比较器选择最大值
            minBy : 根据比较器选择最小值
            reducing: 归约产生类型
            collectingAndThen : 包括另外一个收集器
            groupingBy : 分组
            partitionBy : 分区
         */

        List<Employee> employeeList = new ArrayList<>();
        Employee e1 = new Employee(1, "张三");
        Employee e2 = new Employee(2, "李四");
        Employee e3 = new Employee(3, "王五");
        Employee e4 = new Employee(4, "王五");

        employeeList.add(e1);
        employeeList.add(e2);
        employeeList.add(e3);
        employeeList.add(e4);


        List<String> collect1 = employeeList.stream().map((x) -> x.getName()).collect(Collectors.toList());
        Set<String> collect2 = employeeList.stream().map((x) -> x.getName()).collect(Collectors.toSet());
        LinkedList<String> collect = employeeList.stream().map((x) -> x.getName()).collect(Collectors.toCollection(() -> new LinkedList<>()));
        Long collect3 = employeeList.stream().collect(Collectors.counting());
        Double collect4 = employeeList.stream().collect(Collectors.averagingInt(x -> x.getId()));
        String collect5 = employeeList.stream().map(x -> x.getName()).collect(Collectors.joining());
        Optional<Integer> collect6 = employeeList.stream().map(x -> x.getId()).collect(Collectors.maxBy((x, y) -> x - y));
        Map<String, List<Employee>> collect7 = employeeList.stream().collect(Collectors.groupingBy(x -> x.getName()));
        System.out.println(collect7);
        Map<Boolean, List<Employee>> collect8 = employeeList.stream().collect(Collectors.partitioningBy(x -> x.equals("王五")));
        System.out.println(collect8);

    }

5 并行流与串行流

并行流就是把一个数据块分成了多个数据块,并且用了不同呢的线程分别处理每个数据块的流.

StreamAPI里面可以通过parallel() 和 sequential() 进行并行流和顺序流的切换.

并行流底层是采用的Fork/Join框架.就是将大任务拆分成小任务,然后小任务进行并行的计算,然后将部分结果进行合并.

Fork/Join采用了工作窃取的模式.

6 Optional类: 尽可能的避免空指针异常

常用方法:
Optional.of(T t) : 创建一个 Optional 实例
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
isPresent() : 判断是否包含值
orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
flatMap(Function mapper):与 map 类似,要求返回值必须是Optional

7. 接口中默认的方法和静态方法

接口可以实现默认的方法使用default修饰符进行修饰,但是也会存在问题.

同时JAVA8里面接口支持静态方法.

问题1: 如果接口的默认方法和抽象类的方法名相同,一个子类同时继承抽象类和实现了接口,那么就是类优先原则,子类实际上是继承的父类的同名方法.

问题2: 如果两个接口都有一个同名的默认方法,如果一个子类同时实现了两个接口,那么子类就必须覆盖同名方法.

相关文章

  • 强大的StreamAPI

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

  • StreamAPI

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

  • StreamAPI

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

  • StreamAPI

  • StreamAPI的并行

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

  • Flink Dag简述

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

  • 写给大忙人的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/lpicmhtx.html