Java8 Stream flatmap中間操作用法解析
stream中的flatmap是stream的一種中間操作,它和stream的map一樣,是一種收集類型的stream中間操作,但是與map不同的是,它可以對stream流中單個元素再進行拆分(切片),從另一種角度上說,使用了它,就是使用了雙重for循環(huán)。
查看Stream源碼中flatmap的方法定義:
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
從方法的定義可以看出,其入?yún)⑹且粋€函數(shù)式接口,該接口的返回類型應該是Stream< ? extends R > 類型的。
從實際需求中查看如何使用flatmap:
需求:有一個補習學校,其中有若干老師教學若干門課程,現(xiàn)在學校有關于數(shù)學教學的通知要傳達給所有學數(shù)學的學生家長,將電子郵件發(fā)送到他們的郵箱中。
注意:一個老師可以教學多個科目,一個老師可以教學多個學生,一個學生可以報名多個科目,一個學生可以有多個家長。
數(shù)據(jù)結(jié)構(gòu)(均省略get/set, toString ,構(gòu)造器):
// 老師
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", "數(shù)學"),
Chinese("2", "漢語"),
Music("3", "音樂"),
English("4", "英語");
}
實際上的處理也比較簡單:
1、找出教學科目為“數(shù)學”的老師;
2、找到這些老師對應的學生;
3、根據(jù)學生找到對應的家長。
直接貼代碼:
public class Test {
// 模擬數(shù)據(jù)
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) {
// 找到所有數(shù)學老師的學生的家長的電話,并找他們開家長會
List<Parents> collect = teacs.stream()
// 過濾數(shù)學老師
.filter(t -> Subject.Math.getValue().equals(t.getSubject()))
// 通過老師找學生
.flatMap(t -> stus.stream().filter(s -> s.getTechId().equals(t.getId())))
// 過濾重復的學生(使用student的equals和hashCode方法)
.distinct()
// 通過學生找家長(這里就簡化為創(chuàng)建家長對象)
.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);
}
}
運行結(jié)果:
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,寫該部分代碼的效果,可能還有優(yōu)化的空間,但是不夠使用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一樣,對于調(diào)用flatmap的流的每一個元素,執(zhí)行flatmap入?yún)⒅械暮瘮?shù)式方法,由于該函數(shù)式方法必須返回一個stream<T>類型的流,這樣對于調(diào)用flatmap的操作來說,就收集了另一種類型(<T>)的流,并在后續(xù)的操作中將<T>類型進行合并,最終產(chǎn)生一個stream<T>的流,而不是一個stream<stream<T>>類型的流。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Java操作redis實現(xiàn)增刪查改功能的方法示例
這篇文章主要介紹了Java操作redis實現(xiàn)增刪查改功能的方法,涉及java操作redis數(shù)據(jù)庫的連接、設置、增刪改查、釋放資源等相關操作技巧,需要的朋友可以參考下2017-08-08
springboot2.0如何通過fastdfs實現(xiàn)文件分布式上傳
這篇文章主要介紹了springboot2.0如何通過fastdfs實現(xiàn)文件分布式上傳,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-12-12
如何解決SpringBoot集成百度UEditor圖片上傳后直接訪問404
在本篇文章里小編給大家整理的是一篇關于如何解決SpringBoot集成百度UEditor圖片上傳后直接訪問404相關文章,需要的朋友們學習下。2019-11-11
mybatis之調(diào)用帶輸出參數(shù)的存儲過程(Oracle)
這篇文章主要介紹了mybatis調(diào)用帶輸出參數(shù)的存儲過程(Oracle),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11

