Java8 Stream flatmap中间操作用法解析

 更新时间:2020年07月15日 10:15:17   作者:像风一样无影无起  
这篇文章主要介绍了Java8 Stream flatmap中间操作用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

stream中的flatmap是stream的一种中间操作,它和stream的map一样,是一种收集类型的stream中间操作,但是与map不同的是,它可以对stream流中单个元素再进行拆分(切片),从另一种角度上说,使用了它,就是使用了双重for循环。

查看Stream源码中flatmap的方法定义:

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)

从方法的定义可以看出,其入参是一个函数式接口,该接口的返回类型应该是Stream< ? extends R > 类型的。

从实际需求中查看如何使用flatmap:

需求:有一个补习学校,其中有若干老师教学若干门课程,现在学校有关于数学教学的通知要传达给所有学数学的学生家长,将电子邮件发送到他们的邮箱中。

注意:一个老师可以教学多个科目,一个老师可以教学多个学生,一个学生可以报名多个科目,一个学生可以有多个家长。

数据结构(均省略get/set, toString ,构造器):

// 老师
public class Teacher {
  private String id;
  private String name;
  private String subject;
}
// 学生
public class Student {
  private String id;
  private String name;
  private String techId;
  // 重写hashCode及equals方法(id及name相同就为同一个学生)
}
// 家长
public class Parents {
  private String id;
  private String name;
  private String chirldId;
  private String email;
}
// 课程
public enum Subject {
  private String value;
  private String desc;
  Subject(String value, String desc) {
    this.value = value;
    this.desc = desc;
  }
  Math("1", "数学"),
  Chinese("2", "汉语"),
  Music("3", "音乐"),
  English("4", "英语");
}

实际上的处理也比较简单:

1、找出教学科目为“数学”的老师;

2、找到这些老师对应的学生;

3、根据学生找到对应的家长。

直接贴代码:

public class Test {
  // 模拟数据
  public static Student s1 = new Student("1", "zhangsan", "001");
  public static Student s2 = new Student("2", "lisi", "001");
  public static Student s3 = new Student("3", "wangwu", "001");
  public static Student s4 = new Student("4", "zhaoliu", "001");
  public static Student s5 = new Student("6", "tianqi", "001");
  public static Student s6 = new Student("6", "tianqi", "002");
  public static Student s7 = new Student("6", "tianqi", "003");
  public static Teacher t1 = new Teacher("001", "xiaoming", Subject.Math.getValue());
  public static Teacher t2 = new Teacher("002", "lihua", Subject.Music.getValue());
  public static Teacher t3 = new Teacher("003", "hanmeimei", Subject.Math.getValue());
  public static Teacher t4 = new Teacher("004", "lihua", Subject.English.getValue());
  public static List<Student> stus = new ArrayList<>();
  public static List<Teacher> teacs = new ArrayList<>();
  static {
    stus.add(s1);
    stus.add(s2);
    stus.add(s3);
    stus.add(s4);
    stus.add(s5);
    stus.add(s6);
    stus.add(s7);
    teacs.add(t1);
    teacs.add(t2);
    teacs.add(t3);
    teacs.add(t4);
  }
 
 
  public static void main(String[] args) {
    // 找到所有数学老师的学生的家长的电话,并找他们开家长会
    List<Parents> collect = teacs.stream()
        // 过滤数学老师
        .filter(t -> Subject.Math.getValue().equals(t.getSubject()))
        // 通过老师找学生
        .flatMap(t -> stus.stream().filter(s -> s.getTechId().equals(t.getId())))
        // 过滤重复的学生(使用student的equals和hashCode方法)
        .distinct()
        // 通过学生找家长(这里就简化为创建家长对象)
        .map(s -> {
          Parents p = new Parents();
          p.setId(UUID.randomUUID().toString());
          p.setChirldId(s.getId());
          p.setName(s.getName().toUpperCase() + "'s Parent");
          p.setEmail((int) (Math.random() * 1000000) + "@qq.com");
          return p;
        })
        .collect(Collectors.toList());
    // 打印到控制台看看
    collect.stream()
        .forEach(System.out::println);
  }
}

运行结果:

Parents{id='3d9312eb-0df5-4ec6-998f-94a32c2253b4', name='LISI's Parent', chirldId='2', telNo='844668@qq.com'}
Parents{id='7f0b92f5-872d-4671-982d-ef1b48840ce3', name='WANGWU's Parent', chirldId='3', telNo='563932@qq.com'}
Parents{id='c318bffd-8c6d-4849-8109-9c686c97fb77', name='ZHAOLIU's Parent', chirldId='4', telNo='108022@qq.com'}
Parents{id='a4ff1bbc-c9b6-4ad2-872c-f4df670c7bb6', name='TIANQI's Parent', chirldId='6', telNo='658956@qq.com'}

如果不使用stream,写该部分代码的效果,可能还有优化的空间,但是不够使用stream处理方式更为简洁,方便:

public class Test {
  public static void main(String[] args) {
    List<Parents> pars = new ArrayList<>();
    Set<Student> targetStudents = new HashSet<>();
    for (Teacher t : teacs) {
      if (t.getSubject().equals(Subject.Math.getValue())) {
        for (Student s : stus) {
          if (s.getTechId().equals(t.getId())) {
            targetStudents.add(s);
          }
        }
      }
    }
    for (Student s : targetStudents) {
      Parents p = new Parents();
      p.setId(UUID.randomUUID().toString());
      p.setChirldId(s.getId());
      p.setName(s.getName().toUpperCase() + "'s Parent");
      p.setEmail((int) (Math.random() * 1000000) + "@qq.com");
      pars.add(p);
    }
    for (Parents p : pars) {
      System.out.println(p);
    }
  }
}

再去看stream中的flatmap方法,它的作用就和他的名字flat一样,对于调用flatmap的流的每一个元素,执行flatmap入参中的函数式方法,由于该函数式方法必须返回一个stream<T>类型的流,这样对于调用flatmap的操作来说,就收集了另一种类型(<T>)的流,并在后续的操作中将<T>类型进行合并,最终产生一个stream<T>的流,而不是一个stream<stream<T>>类型的流。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Java操作redis实现增删查改功能的方法示例

    Java操作redis实现增删查改功能的方法示例

    这篇文章主要介绍了Java操作redis实现增删查改功能的方法,涉及java操作redis数据库的连接、设置、增删改查、释放资源等相关操作技巧,需要的朋友可以参考下
    2017-08-08
  • springboot2.0如何通过fastdfs实现文件分布式上传

    springboot2.0如何通过fastdfs实现文件分布式上传

    这篇文章主要介绍了springboot2.0如何通过fastdfs实现文件分布式上传,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • java线程池中线程数量到底是几

    java线程池中线程数量到底是几

    本文主要介绍了java线程池中线程数量到底是几,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • java之super关键字用法实例解析

    java之super关键字用法实例解析

    这篇文章主要介绍了java之super关键字用法实例解析,较为详细的分析了super关键字的用法及内存分布,需要的朋友可以参考下
    2014-09-09
  • 如何解决SpringBoot集成百度UEditor图片上传后直接访问404

    如何解决SpringBoot集成百度UEditor图片上传后直接访问404

    在本篇文章里小编给大家整理的是一篇关于如何解决SpringBoot集成百度UEditor图片上传后直接访问404相关文章,需要的朋友们学习下。
    2019-11-11
  • 二叉树递归迭代及morris层序前中后序遍历详解

    二叉树递归迭代及morris层序前中后序遍历详解

    这篇文章主要为大家介绍了二叉树递归迭代详解及二叉树的morris遍历、层序遍历、前序遍历、中序遍历、后序遍历示例分析,有需要的朋友可以借鉴参考下
    2021-11-11
  • idea导入module全流程

    idea导入module全流程

    这篇文章主要介绍了idea导入module全流程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • java实现文件断点续传下载功能

    java实现文件断点续传下载功能

    这篇文章主要为大家详细介绍了java实现文件断点续传下载功能的具体代码,感兴趣的小伙伴们可以参考一下
    2016-05-05
  • mybatis之调用带输出参数的存储过程(Oracle)

    mybatis之调用带输出参数的存储过程(Oracle)

    这篇文章主要介绍了mybatis调用带输出参数的存储过程(Oracle),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • SpringCloud启动失败问题汇总

    SpringCloud启动失败问题汇总

    这篇文章主要介绍了SpringCloud启动失败问题汇总,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03

最新评论