java8(2)--- Stream API

1.简述

Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一 个就是 Stream API。

Stream 是处理集合的抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询,比如可以实现group by的分组操作。总之就是Stream API提供的高效简介的数据处理方式。

流(Stream)是什么?心脏的血液通过血管流变全身,在血管中的时候就可以看做流,生病了需要通过血管进行输液,也就是说在这个流中进行了操作。心脏的血液可以看做一个数据集合,转换成流通过血管进行输送,输液这个操作就相当于是我们Stream API 所做的操作,也就是对这个流进行计算处理。

集合是数据,流是计算。

需要注意的是:

  1.Stream 自己不会存储元素。

  2.Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

  3.Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

Stream三步走:

  1.创建流

  2.操作流

  3.终止操作获取结果,注意:流进行了终止操作后,不能再次使用

2.API操作案例

  2.1.创建流

        //集合创建流
        Stream<Student> stream1 = studentList.stream();

        //Stream静态方法创建流
        Stream<Student> stream2 = Stream.of(
                new Student(1, "张三", 12, 69),
                new Student(2, "李四", 12, 78.5),
                new Student(3, "王五", 13, 95),
                new Student(4, "赵六", 14, 23),
                new Student(5, "孙七", 11, 55.5)
        );
        //数组创建流
        Stream<Student> stream = Arrays.stream(new Student[]{});

  2.2.操作流

    2.2.1 筛选和分割

      filter(Predicate p) 接收 Lambda , 从流中排除某些元素。

      distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素,切记重写

      limit(long maxSize) 截断流,使其元素不超过给定数量。limit取值找到符合条件的就结束了 不会继续查找所有

      skip(long n) 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补

        //filter过滤年龄大于12的
        studentList.stream()
                .filter(student -> student.getAge() > 12)
                .forEach(System.out::println);
        System.out.println("--------------");

        //distinct去重
        studentList.stream()
                .distinct()
                .forEach(System.out::println);
        System.out.println("--------------");

        //过滤之后取前2,有点类似mysql的limit了,
        // limit取值找到符合条件的就结束了 不会继续查找所有,下面的输出语句只会执行2次,因为前面两个就是满足条件的
        studentList.stream()
                .filter((student) -> {
                        System.out.println("执行过滤");
                        return student.getAge() >= 12;
                })
                .limit(2)
                .forEach(System.out::println);
        System.out.println("--------------");

        //skip跳过满足条件前两个
        studentList.stream()
                .filter(student ->  student.getAge() >= 12)
                .skip(2)
                .forEach(System.out::println);

    2.2.2 映射

      map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素

      flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

      有点类似list的 add方法和addAll,一个添加单个元素到集合中,一个是将集合中元素逐一添加到另一个集合中

    public void testStream2() {

        //将map中的函数应用到每个元素上,生成一个新的元素,也就是收集每个student的名字组成一个新的元素
        studentList.stream()
                .distinct()
                .map(student -> student.getName())
                .forEach(System.out::println);
        System.out.println("--------");
        //调用creatStream方法将每个Student对象都转换成一个流,然后flatMap将每个流汇总成一个流
        studentList.stream()
                .distinct()
                .flatMap(StreamTest::creatStream)
                .forEach(System.out::println);
    }
    public static Stream<Student> creatStream(Student student){
        return Stream.of(student);
    }

    2.2.3 排序

      sorted() 产生一个新流,其中按自然顺序排序

      sorted(Comparator comp) 产生一个新流,其中按比较器顺序排序

  2.3 流结果获取

    2.3.1查找与匹配 

      allMatch(Predicate p) 检查是否匹配所有元素

      anyMatch(Predicate p) 检查是否至少匹配一个元素

      noneMatch(Predicate p) 检查是否没有匹配所有元素

      findFirst() 从流的操作中返回第一个元素(封装在Optional中)

      findAny() 返回当前流中的任意元素(封装在Optional中),并行流结果有随机性

      count() 返回流中元素总数

      max(Comparator c) 返回流中最大值 (封装在Optional中)

      min(Comparator c) 返回流中最小值 (封装在Optional中)

      forEach(Consumer c) 内部迭代

     //allMatch(Predicate p) 检查是否匹配所有元素 是否所有student age > 12
        boolean result = studentList.stream()
                .allMatch(student -> student.getAge() > 12);
        System.out.println(result);

        //anyMatch(Predicate p) 检查是否至少匹配一个元素
        result = studentList.stream()
                .anyMatch(student -> student.getAge() == 12);
        System.out.println(result);

        //noneMatch(Predicate p) 检查是否没有匹配所有元素
        result = studentList.stream()
                .noneMatch(student -> student.getAge() < 11);
        System.out.println(result);
        //findFirst() 从流的操作中返回第一个元素(封装在Optional中)
        //按score升序 之后取第一个
        Student student = studentList.stream()
                .sorted((student1, student2) -> Double.compare(student1.getScore(), student2.getScore()))
                .findFirst()
                .get();
        System.out.println(student);

        student = studentList.stream()
                .findAny()
                .get();
        System.out.println(student);

    2.3.2 归约

      reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T

      reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 Optional<T>

      map 和 reduce 的连接通常称为 map-reduce 模式

        //累加,将流中元素进行求和
        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);

        //求student的总分
        Double allScore = studentList.stream()
                .map(student -> student.getScore())
                .reduce(Double::sum)
                .get();
        System.out.println(allScore);

    2.3.3 收集     

      collect(Collector c) 将流转换为其他形式。接收一个 Collector接口(收集器)的实现,用于给Stream中元素做汇总的方法

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

      1.8提供了Collectors 工具类可以方便地创建常见收集器实例

Collectors:

        List<Student> studentList = Arrays.asList(
                new Student(1, "张三", 12, 69, Student.Clazz.Clazz2),
                new Student(2, "李四", 12, 78.5,Student.Clazz.Clazz2),
                new Student(3, "王五", 13, 95, Student.Clazz.Clazz3),
                new Student(4, "赵六", 14, 23, Student.Clazz.Clazz3),
                new Student(5, "孙七", 11, 55.5, Student.Clazz.Clazz1),
                new Student(5, "孙七", 11, 55.5, Student.Clazz.Clazz1)
        );

        //toList() 收集到List集合中
        List<String> nameList = studentList.stream()
                .map(student -> student.getName())
                .collect(Collectors.toList());
        System.out.println(nameList);
        //toSet() 收集到Set集合中 自动去重 默认返回的HashSet
        Set<String> nameSet= studentList.stream()
                .map(student -> student.getName())
                .collect(Collectors.toSet());
        System.out.println(nameSet);
        System.out.println(nameSet.getClass());
        //返回指定集合类型
        TreeSet<String> nameTreeSet= studentList.stream()
                .map(student -> student.getName())
                .collect(Collectors.toCollection(TreeSet::new));
        System.out.println(nameTreeSet.getClass());

        //分组groupingBy 返回map集合 类似sql group by了
        //根据年级分组
        Map<Student.Clazz, List<Student>> map = studentList.stream()
                .collect(Collectors.groupingBy(Student::getClazz));
        System.out.println(map);
        //多次分组
        //先按年级再按年龄
        Map<Student.Clazz, Map<Integer, List<Student>>> map2 = studentList.stream()
                .collect(Collectors.groupingBy(Student::getClazz, Collectors.groupingBy(Student::getAge)));
        System.out.println(map2);

        //分区partitioningBy 入参是个断言型接口
        studentList.stream()
                .collect(Collectors.partitioningBy((student) -> student.getScore() >= 60));

        //summarizingDouble 对某个值进行 数据统计输出
        //对score进行统计
        DoubleSummaryStatistics statistics = studentList.stream()
                .collect(Collectors.summarizingDouble(Student::getScore));
        statistics.getAverage();
        statistics.getCount();
        statistics.getMax();
        statistics.getMin();
        statistics.getSum();

Student类:

    private int id;
    private String name;
    private int age;
    private double score;
    private Clazz clazz;

    public Student(String name) {
        this.name = name;
    }

    public Student(int id, String name, int age, double score) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public Student(int id, String name, int age, double score, Clazz clazz) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.score = score;
        this.clazz = clazz;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    public Clazz getClazz() {
        return clazz;
    }

    public void setClazz(Clazz clazz) {
        this.clazz = clazz;
    }

    public String show() {
        return "测试方法引用";
    }

    @Override
    public int hashCode() {
        final int prime = 11;
        int hashCode = 1;
        hashCode = prime * hashCode + age;
        hashCode = prime * hashCode + id;
        hashCode = prime * hashCode + ((name == null) ? 0 : name.hashCode());
        long temp;
        temp = Double.doubleToLongBits(score);
        hashCode = prime * hashCode + (int) (temp ^ (temp >>> 32));
        return hashCode;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }

        if (getClass() != obj.getClass()) {
            return false;
        }
        Student other = (Student) obj;
        if (age != other.age) {
            return false;
        }

        if (id != other.id) {
            return false;
        }
        if (name == null) {
            if (other.name != null) {
                return false;
            }
        } else if (!name.equals(other.name)) {
            return false;
        }
        if (Double.doubleToLongBits(score) != Double.doubleToLongBits(other.score)) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "[id=" + id + ", name=" + name + ", age=" + age + ", score=" + score + ", Class=" + clazz + "]";
    }

    public static enum Clazz{
        Clazz1,
        Clazz2,
        Clazz3,
    }

原文地址:https://www.cnblogs.com/nijunyang/p/11334814.html

时间: 2024-11-06 03:52:16

java8(2)--- Stream API的相关文章

Java8初体验(二)Stream语法详解

原文链接:http://ifeve.com/stream/ 1. Stream初体验 我们先来看看Java里面是怎么定义Stream的: A sequence of elements supporting sequential and parallel aggregate operations. 我们来解读一下上面的那句话: Stream是元素的集合,这点让Stream看起来用些类似Iterator: 可以支持顺序和并行的对原Stream进行汇聚的操作: 大家可以把Stream当成一个高级版本的

【转】Java8初体验(二)Stream语法详解

原文链接 http://ifeve.com/stream/ Java8初体验(二)Stream语法详解 感谢同事[天锦]的投稿.投稿请联系 [email protected]上篇文章Java8初体验(一)lambda表达式语法比较详细的介绍了lambda表达式的方方面面,细心的读者会发现那篇文章的例子中有很多Stream的例子.这些Stream的例子可能让你产生疑惑,本文将会详细讲解Stream的使用方法(不会涉及Stream的原理,因为这个系列的文章还是一个快速学习如何使用的). 1. Str

Docker入门教程(七)Docker API

Docker入门教程(七)Docker API [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第七篇,重点介绍了Docker Registry API和Docker Hub API. 纵观我们的Docker系列教程,我们已经讨论了很多重要的Docker组件与命令.在本文中,我们将继续深入学习Docker:剖析Docker APIs. Docker提供了很多的API以便用户使用.这些API包含四个方面: Docker Registry API Doc

漫谈可视化Prefuse(三)---Prefuse API数据结构阅读有感

前篇回顾:上篇<漫谈可视化Prefuse(二)---一分钟学会Prefuse>主要通过一个Prefuse的具体实例了解了构建一个Prefuse application的具体步骤.一个Prefuse Application需要经过数据导入(文本数据.数据库)->Prefuse数据结构接收数据->注册各种效果的Actions->渲染Renderer->交互展现Display的流程. 摸清了Prefuse那些看似眼花缭乱的框架结构,剩下的就是抽丝剥茧,顺藤摸瓜,结合Manua

HBase概念学习(三)Java API之扫描和过滤器

HBase基本的CRUD操作就不多介绍了,无非就是Put,Get,Delete三个类的运用. 本文相当于是阅读HBase权威指南的总结. 一.扫描(Scan) 现在看一下扫描技术,这种技术类似于关系型数据库的游标(cursor),并利用到了HBase底层顺序存储的特性. 使用扫描的一般步骤是: 1.创建Scan实例 2.为Scan实例增加扫描的限制条件 3.调用HTable的getScanner()方法获取ResultScanner对象 4.迭代ResultScanner对象中的Result对象

(转载)pThreads线程(一) 基本API

pThreads线程(一) 基本API 1.创建线程  int pthread_create(pthread_t *restrict_ptid,              const pthread_attr_t *restrict_attr,              void *(*start_routine)(void*), void *restrict_arg);      ptid是一个pthread_t *类型的指针,pthread_t是类似pid_t的数据结构,表示线程ID:att

Java8新特性(1)—— Stream集合运算流入门学习

废话,写在前面 好久没写博客了,懒了,以后自觉写写博客,每周两三篇吧! 简单记录自己的学习经历,算是对自己的一点小小的督促! Java8的新特性很多,比如流处理在工作中看到很多的地方都在用,是时候扔掉笨重的for循环了!节省40%-50%代码量!Come on! 如题 (总结要点) Stream API只能被消费一次,后续重复使用已建立的流会报异常!所以stream流是线程安全的! 比如执行"stream.forEach(System.out::println);stream.forEach(S

Java8两大特性(一)——Stream

什么是Stream? Stream(流)是一个来自数据源的元素队列并且支持聚合操作,元素流在管道中经过中间操作,最终操作得到结果. 数据源:集合,数组,I/O channel,产生器generator. 聚合操作:类似于sql比如:filter,find,map,match,sorted. 生成流: stream() − 为集合创建串行流. parallelStream() − 为集合创建并行流. 通过例子看方法: list.stream().limit(10).sorted().forEach

JAVA8新特性之 Stream API

重要的 Stream API  : java.util.Stream.* Stream提供了一种高效且简易处理数据的方式 注意:1.Stream自己不会存储元素 2.对Stream进行操作不会改变数据源,相反,会产生一个执有结果的新Stream 3.Stream操作是延迟执行的.只有进行了终止操作才会产生结果 (并行流就是把内容分成多个数据块,并用不同的线程分别处理每个数据块.在Java8 后,Stream API可以声明性的通过parallel()与sequential()在并行流与串行流(顺