Stream流中的Map与flatMap的理解

map比较简单,可以抽取列表元素的某个属性形成新的列表,但是无法对更深层的属性做提取,相当于只针对一维数组,一对一的处理。

flatMap主要是对流进行扁平化,可以将一个2维的集合映射成一个一维,相当于他映射的深度比map深了一层 ,所以名称上就把map加了个flat,叫flatmap;而他针对的也是二维数组,一对多的处理。

开发时,可以使用的idea的debug看到stream的处理过程,每一步是怎么处理的。

前言

用法区别

map自动返回stream对象;

flatmap处理后的元素依然要是stream对象(可以用stream.of,Arrays.stream将元素转为stream对象),这也是flatMap和map的用法区别,flatmap需要再加一个Arrays.stream或stream.of或者方法引用,而map不用。

简单写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
List<String> list = Arrays.asList("a1","a2","a3");

// map的用法
// 一对一的处理,在每个字符串后面加上test输出
list.stream().map(s->s+"test").forEach(System.out::println);
// 输出
a1test
a2test
a3test


// flatMap的两种用法
// 一对多的处理,把每个字符串拆成一个个字符,输出,这点map就无法做到。
ArrayList<String> list = Lists.newArrayList();
list.add("111,222");
list.add("121");
list.add("131");
List<String> collect = list.stream().flatMap(s -> Stream.of(s.split(","))).collect(Collectors.toList());
// 输出
[111222, 121, 131]

需求

比如遇到如下需求:给List<Room>对象,需要获取到List<String> peopleNameList对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 解释:一个房间有自己的房间号,里面有一堆人,每个人都有名字
@Data
@AllArgsConstructor
@NoArgsConstructor
static class Room {
private int number;
private List<People> peopleList;


@Data
@NoArgsConstructor
@AllArgsConstructor
static class People {
private String name;
}
}

解决方案

使用Map方法

如果只是使用普通的map方法且里面是直接getPeopleList()方法,则得到的是 List<List<Room.People>> collect 对象。

1
2
3
4
5
6
7
8
public class Demo {
public static void main(String[] args) {
final List<Room> roomList = initRoom();
List<List<Room.People>> collect = roomList.stream()
.map(Room::getPeopleList)
.collect(Collectors.toList());
}
}

通常遇到这情况,一般人解决就是在遍历一次,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Demo {
public static void main(String[] args) {
final List<Room> roomList = initRoom();
List<List<Room.People>> collect = roomList.stream()
.map(Room::getPeopleList)
.collect(Collectors.toList());
// 1.先new ArrayList<>() 准备存储String字符串
List<String> peopleNameList = new ArrayList<>();
// 2. 这里就得套两层的foreach了
// 因为初始化是List<List<T>>对象
// 第一次foreach中peopleList 是List<Room.People>对象
collect.forEach(peopleList -> {
// 第二次foreach中people 是People对象
peopleList.forEach(people -> {
peopleNameList.add(people.getName());
});
});
}

而有的人可能会在上面的基础上,再进一步优化为如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Demo {
public static void main(String[] args) {
final List<Room> roomList = initRoom();

List<String> peopleNameList = new ArrayList<>();
// 直接一直使用stream流的foreach
// 虽然是比上面代码优雅多了,但两个foreach,怎么看都不舒服
roomList.stream().forEach(room -> {
room.getPeopleList().forEach(people -> {
peopleNameList.add(people.getName());
});
});
}
}

使用flatMap

flatMap就是用于多层结构的扁平化,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Demo {
public static void main(String[] args) {
final List<Room> roomList = initRoom();

List<String> peopleNameList = roomList.stream()
// 跟之前一样,生成多层list
.map(Room::getPeopleList)
// 直接使用flatMap,使其压缩成一个list
.flatMap(Collection::stream)
// 之后正常操作扁平化的数据即可
.map(Room.People::getName)
.collect(Collectors.toList());
}
}

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class Demo {
public static void main(String[] args) {
final List<Room> roomList = initRoom();

// Map方法
List<String> peopleNameList = new ArrayList<>();

roomList.stream().forEach(room -> {
room.getPeopleList().forEach(people -> {
peopleNameList.add(people.getName());
});
});

// flatMap 方法
List<String> peopleNameList2 = roomList.stream()
.map(Room::getPeopleList)
.flatMap(Collection::stream)
.map(Room.People::getName)
.collect(Collectors.toList());
}

// 初始化10条数据
private static List<Room> initRoom() {
return IntStream.range(1, 11)
.mapToObj(num -> new Room(num, Arrays.asList(new Room.People("name:" + num), new Room.People("name:" + 10 * num))))
.collect(Collectors.toList());
}

@Data
@AllArgsConstructor
@NoArgsConstructor
static class Room {
private int number;
private List<People> peopleList;


@Data
@NoArgsConstructor
@AllArgsConstructor
static class People {
private String name;
}
}
}
点击查看

本文标题:Stream流中的Map与flatMap的理解

文章作者:LiJing

发布时间:2023年06月10日 - 18:08:16

最后更新:2023年06月10日 - 18:23:19

原始链接:https://blog-next.xiaojingge.com/posts/2608521979.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------------本文结束 感谢您的阅读-------------------