目 录CONTENT

文章目录

Stream流中的Map与flatMap的理解

筱晶哥哥
2023-06-10 / 0 评论 / 0 点赞 / 65 阅读 / 9684 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2024-03-23,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

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不用。

简单写法

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对象

// 解释:一个房间有自己的房间号,里面有一堆人,每个人都有名字
@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 对象。

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());
            });
        });
    }
}

使用flatMap

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

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());
    }
}

完整代码

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;
        }
    }
}
0

评论区