Java8 Stream flatmap中间操作用法解析

网友投稿 331 2022-12-01


Java8 Stream flatmap中间操作用法解析

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

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

Stream 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;

zGlFDYjprivate 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 stus = new ArrayList<>();

public static List 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 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()

// 通过学生找家长(这里就简化为创建家长http://对象)

.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 pars = new ArrayList<>();

Set 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类型的流,这样对于调用flatmap的操作来说,就收集了另一种类型()的流,并在后续的操作中将类型进行合并,最终产生一个stream的流,而不是一个stream>类型的流。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:SpringBoot 中大文件(分片上传)断点续传与极速秒传功能的实现
下一篇:Java调用腾讯云短信API接口的实现
相关文章

 发表评论

暂时没有评论,来抢沙发吧~