【Java8】 map和flatMap的使用

map方法

        流支持map方法,接受一个函数作为参数。这个函数会被应用到每一个元素上,并将其映射成一个新的元素 。例如:Dish::getName 传给了map方法,用来提取菜肴的名称。getName 方法返回的是一个String,所以map方法输出的流
的类型就是Stream<String>。

// 获取名字的长度
    @Test
    public void testMap() {
        ArrayList<String> words = Lists.newArrayList("java8", "Lambdas", "in");
        List<Integer> collect = words.stream()
                .map(String::length)
                .collect(Collectors.toList());

        Map<String, Integer> collect1 = words.stream().collect(Collectors.toMap(i -> i, i -> i.length()));
        logger.info("words 长度是:{}", collect); //words 长度是:[5, 7, 2]
        logger.info("collect1 map是:{}", collect1);//{Lambdas=7, in=2, java8=5}
    }

flatMap方法

   遇到的场景是,对于给定的单词表["hello","world"],你想要得到的是["H","e","l", "o","W","r","d"],单独的使用map方法

 List<String[]> collect2 = words.stream()
                .map(word -> word.split(""))
                .distinct()
                .collect(toList());

 map实际上返回的是Stream<String[]>类型的, 但是真正想要的是Stream<String> 来表示一个字符流。使用map的图解

    需要的是一个字符流,而不是数组流。又一个叫做Arrays.stream()的方法可以接受一个数并产生一个流。
    可以使用flatMap来解决这个问题
    使用flatMap的效果,各个数组不是分别映射成一个流,而是映射成流的内容。所有使用map(Arrays::stream)时生成的
    单个流都被合并起来,既扁平化成一个一个流,图解如下:

   

一言以蔽之,flatMap方法会让给你把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流。

  同样下面的这个图,对于flatMap的说明感觉很形象。

     

demo 练习

例如有以下的需求,一个字符串数组{"hello","word"},想得到所有的单个字符号["h","e","l","l","o","w","o","r","d"],会如何做呢?原来内容实现方法会这样:

 @Test
    public void testFlatMap() {
        Gson gson = new Gson();
        String[] helloStr = {"hello", "word"};

        List<String> list = Lists.newArrayList();
        Arrays.stream(helloStr)
                .forEach(str -> {
                    List<String> collect1 = Arrays.stream(str.split("")).collect(Collectors.toList());
                    list.addAll(collect1);
                });
        logger.info("list 结果是:{}", gson.toJson(list));
        //这是原来解决方法 (分层剥离,然后合并到一个list中去)
        // list 结果是:["h","e","l","l","o","w","o","r","d"]
    }

使用flatMap实现

 @Test
    public void testFlatMap() {
        Gson gson = new Gson();
        String[] helloStr = {"hello", "word"};
       
        //分步写(流只能消费一次)(flatMap)
        Stream<String[]> stream1 = Arrays.asList(helloStr).stream().
                map(str -> str.split(""));

        Stream<String> stringStream = stream1.flatMap(strings1 -> Arrays.stream(strings1));

        List<String> stringList1 = stringStream.collect(Collectors.toList());
        logger.info("结果是:{}", gson.toJson(stringList1));
        //结果是:["h","e","l","l","o","w","o","r","d"]

        //最后汇总写法
        List<String> newList = Arrays.stream(helloStr)
                .map(str -> str.split(""))
                .flatMap(str -> Arrays.stream(str))
                .collect(Collectors.toList());
        logger.info("newList 结果是:{}", gson.toJson(newList));
        //newList 结果是:["h","e","l","l","o","w","o","r","d"]
        //https://www.cnblogs.com/java-le/p/7909729.html 讲解

    }

嵌套两层的科目树等,结构如下:

[
    {
        "id":1,
        "name":"河北",
        "parent":0,
        "children":[
            {
                "id":2,
                "name":"邯郸",
                "parent":1,
                "children":[
                    {
                        "id":3,
                        "name":"成安",
                        "parent":2,
                        "children":[

                        ]
                    }
                ]
            }
        ]
    },
    {
        "id":4,
        "name":"北京",
        "parent":0,
        "children":[
            {
                "id":5,
                "name":"北京市",
                "parent":4,
                "children":[
                    {
                        "id":6,
                        "name":"朝阳区",
                        "parent":5,
                        "children":[

                        ]
                    }
                ]
            }
        ]
    }
]

获取最低级的县或者区的信息,使用flatMap获取

 @Test
    public void flatMap() {
        Gson gson = new Gson();
        List<TreeVo> treeVos = TreeVo.getTreeList();
        System.out.println("所有的树结构是:{}" + gson.toJson(treeVos));
      
      //所有的树结构是:[{"id":1,"name":"河北","parent":0,"children":[{"id":2,"name":"邯郸","parent":1,"children":[{"id":3,"name":"成安","parent":2,"children":[]}]}]},{"id":4,"name":"北京","parent":0,"children":[{"id":5,"name":"北京市","parent":4,"children":[{"id":6,"name":"朝阳区","parent":5,"children":[]}]}]}]
       
     List<TreeVo> collect = treeVos.stream().flatMap(list ->
                list.getChildren().stream().flatMap(vo -> vo.getChildren().stream())
        ).collect(Collectors.toList());
        System.out.println("结果是:{}" + gson.toJson(collect));
       
     //[{"id":3,"name":"成安","parent":2,"children":[]},{"id":6,"name":"朝阳区","parent":5,"children":[]}]
    }

 经常用的场景是List<list<T>>类型的结构,如下 List<List<StudentEntity>> 类型

 /**
     * List<List<StudentEntity>> 类型
     */
    @Test
    public void flatMapStudent() {
        Gson gson = new Gson();
        List<List<StudentEntity>> filterStudent = StudentEntity.getFilterStudent();
        logger.info("filterStudent:{}", gson.toJson(filterStudent));
       // filterStudent:[[{"userId":4,"userName":"第二个小红","age":4,"child":[]},{"userId":5,"userName":"第二个小花","age":5,"child":[]},{"userId":6,"userName":"第二个小黄","age":6,"child":[]}],[{"userId":1,"userName":"第一个小红","age":1,"child":[]},{"userId":2,"userName":"第一个小花","age":2,"child":[]},{"userId":3,"userName":"第一个小黄","age":3,"child":[]}]]
        Set<String> collect = filterStudent.stream().flatMap(Collection::stream)
                .map(StudentEntity::getUserName)
                .collect(Collectors.toSet());
        logger.info("结果是:{}", collect);
        //结果是:[第二个小花, 第二个小红, 第二个小黄, 第一个小红, 第一个小花, 第一个小黄]
    }

 

参考博客

https://www.cnblogs.com/diegodu/p/8794857.html  

https://www.cnblogs.com/java-le/p/7909729.html

小结

        主要是为了区分下,何时会使用flatMap,现在感觉是flatMap 适用于 List<List<object>> 这种类型的结果,数组里面包含一个数组,但是想获取object每个元素,可以使用这个

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值