0. 先说结论
- map的作用:是将输入一种类型,转化为另一种类型,通俗来说:就是将输入类型变成另一个类型。
- flatMap的作用:是扁平化的,比如有对象
List<List<User>> userLists
, 这属于套娃现象,而最终我们只想得到List<User> userList
对象,即将多维集合,变成一个集合,相当于压缩,俗称扁平化。
1. 需求
-
之前在做开发的时候,遇到如下需求:
给List<Room>
对象,需要获取到List<String> peopleNameList
对象// 解释:一个房间有自己的房间号,里面有一堆人,每个人都有面子 @Data @AllArgsConstructor @NoArgsConstructor static class Room { private int number; private List<People> peopleList; @Data @NoArgsConstructor @AllArgsConstructor static class People { private String name; } }
2. 解决方案
1. 使用Map方法
-
如下:如果只是使用普通的map方法且里面是直接getPeopleList()方法,则得到的是
List<List<Room.People>> collect
对象。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()); } }
-
通常遇到这情况,一般人解决就是在遍历一次,如下:
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()); }); }); }
-
而有的人可能会在上面的基础上,再进一步优化为如下:
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()); }); }); } }
2. 使用flatMap解决
-
flatMap就是用于多层结构的扁平化,如下:
public class demo { public static void main(String[] args) { final List<Room> roomList = initRoom(); List<String> peopleNameList = roomList.stream() .map(Room::getPeopleList) .flatMap(Collection::stream) .map(Room.People::getName) .collect(Collectors.toList()); } }
3. 完整代码
-
代码如下:
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; } } }