美文网首页Java基础
java8中map和flatMap区别

java8中map和flatMap区别

作者: 大橙子Hi | 来源:发表于2019-07-24 14:02 被阅读0次

    1.函数定义比较

    map注释

        /**
         * Returns a stream consisting of the results of applying the given
         * function to the elements of this stream.
         *
         * <p>This is an <a href="package-summary.html#StreamOps">intermediate
         * operation</a>.
         *
         * @param <R> The element type of the new stream
         * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
         *               <a href="package-summary.html#Statelessness">stateless</a>
         *               function to apply to each element
         * @return the new stream
         */
        <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    

    翻译过来:

    返回由将给定函数应用于该流元素的结果组成的流。
    这是一个中间操作。
    
    参数:
        映射器-适用于每个元素的无干扰、无状态功能
    类型参数:
        新流的元素类型
    返参:新流
    

    也就是说你的集合中的元素是什么类型就返回该元素的流。

    flatMap注释:

        /**
         * Returns a stream consisting of the results of replacing each element of
         * this stream with the contents of a mapped stream produced by applying
         * the provided mapping function to each element.  Each mapped stream is
         * {@link java.util.stream.BaseStream#close() closed} after its contents
         * have been placed into this stream.  (If a mapped stream is {@code null}
         * an empty stream is used, instead.)
         *
         * <p>This is an <a href="package-summary.html#StreamOps">intermediate
         * operation</a>.
         *
         * @apiNote
         * The {@code flatMap()} operation has the effect of applying a one-to-many
         * transformation to the elements of the stream, and then flattening the
         * resulting elements into a new stream.
         *
         * <p><b>Examples.</b>
         *
         * <p>If {@code orders} is a stream of purchase orders, and each purchase
         * order contains a collection of line items, then the following produces a
         * stream containing all the line items in all the orders:
         * <pre>{@code
         *     orders.flatMap(order -> order.getLineItems().stream())...
         * }</pre>
         *
         * <p>If {@code path} is the path to a file, then the following produces a
         * stream of the {@code words} contained in that file:
         * <pre>{@code
         *     Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8);
         *     Stream<String> words = lines.flatMap(line -> Stream.of(line.split(" +")));
         * }</pre>
         * The {@code mapper} function passed to {@code flatMap} splits a line,
         * using a simple regular expression, into an array of words, and then
         * creates a stream of words from that array.
         *
         * @param <R> The element type of the new stream
         * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
         *               <a href="package-summary.html#Statelessness">stateless</a>
         *               function to apply to each element which produces a stream
         *               of new values
         * @return the new stream
         */
        <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
    

    翻译过来:

    返回由将该流的每个元素替换为通过将所提供的映射功能应用到每个元素而产生的映射流的内容的结果组成的流。每个映射的流在其内容已被放置到该流中之后被关闭。(如果映射的流是空的,则使用空的流。)
        
    这是一个中间操作。
    
    参数:
        映射器-无干扰、无状态功能,适用于产生新数值流的每个元素
    类型参数:
        新流的元素类型
    返参:
        新流
    Apinote:
        FlatMap()操作具有对该流的元素应用一对多变换的效果,然后将所得到的元素展平到新的流中。
    案例.
      如果订单是采购订单的流,并且每个采购订单包含一系列行项目,则以下将生成包含所有订单中所有行项目的流:
       orders.flatMap(order -> order.getLineItems().stream())... 
      如果路径是到文件的路径,则以下会产生包含在该文件中的单词的流:
        Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8);
        Stream<String> words = lines.flatMap(line -> Stream.of(line.split(" +")));
      传递到FlatMap的映射器函数使用简单正则表达式将一行分割为单词数组,然后从该数组创建一个单词流 
    

    我的理解是假如你的集合流中包含子集合,那么使用flatMap可以返回该子集合的集合流.

    2.案例比较

    假如我们有地址类,一个地址类包含多个城市将地址类作为集合,我们想输出所有的城市的名字。

    数据结构:

    1.jpg

    地址类

    //地址类
    public class Address {
        private String province;
        private List<String> cityList;//市集合
        public String getProvince() {
            return province;
        } 
        public void setProvince(String province) {
            this.province = province;
        }
    
        public List<String> getCityList() {
            return cityList;
        }
    
        public void setCityList(List<String> cityList) {
            this.cityList = cityList;
        }
    
        @Override
        public String toString() {
            return "Address{" +
                    "province='" + province + '\'' +
                    ", cityList=" + cityList +
                    '}';
        }
    }
    

    测试案例

        public static void main(String[] args) {
    
            List<String> cityListOne = new ArrayList<>();
            cityListOne.add("郑州");
            cityListOne.add("濮阳");
            List<String> cityListTwo = new ArrayList<>();
            cityListTwo.add("廊坊");
            cityListTwo.add("邢台");
            List<String> cityListThree = new ArrayList<>();
            cityListThree.add("大同");
            cityListThree.add("太原");
            List<String> cityListFour = new ArrayList<>();
            cityListFour.add("南昌");
            cityListFour.add("九江");
    
            Address addressOne = new Address();
            addressOne.setProvince("河南");
            addressOne.setCityList(cityListOne);
    
            Address addressTwo = new Address();
            addressTwo.setProvince("河北");
            addressTwo.setCityList(cityListTwo);
    
            Address addressThree = new Address();
            addressThree.setProvince("山西");
            addressThree.setCityList(cityListThree);
    
            Address addressFour = new Address();
            addressFour.setProvince("江西");
            addressFour.setCityList(cityListFour);
    
            List<Address> addresseList = new ArrayList<>();
            addresseList.add(addressOne);
            addresseList.add(addressTwo);
            addresseList.add(addressThree);
            addresseList.add(addressFour);
    
            //使用map输出所有的城市名称
            addresseList.stream()
                    .map(a -> a.getCityList())
                    .forEach(cityList->{ cityList.forEach(city -> System.out.print(city));
            });
            System.out.println("");
            //使用flatMap输出所有城市名称
            addresseList.stream()
                    .flatMap(a -> a.getCityList().stream())
                    .forEach(city -> System.out.print(city));
    
    
        }
    
    

    输出结果

    郑州濮阳廊坊邢台大同太原南昌九江
    郑州濮阳廊坊邢台大同太原南昌九江
    

    可以看出两个循环结果一致,但是map处理方式是在foreach中将cityList作为集合再次循环,而flatMap可以直接将cityList中的城市直接进行循环输出。也就是说flatMap可以获取集合中的集合的流在外层可以直接处理

    3.map强行获取流会如何?

    如果我们使用map强行获取流进行循环会如何呢?

    
    
            //使用map输出所有的城市名称
            addresseList.stream()
                    .map(a -> a.getCityList())
                    .forEach(cityList->{ cityList.forEach(city -> System.out.print(city));
            });
      
            //使用map强行获取流进行输出,写法和flatMap一致
            addresseList.stream()
                    .map(a -> a.getCityList().stream())
                    .forEach(city->System.out.println(city));
     
            //使用flatMap输出所有城市名称
            addresseList.stream()
                    .flatMap(a -> a.getCityList().stream())
                    .forEach(city -> System.out.print(city));
    

    打印结果:

    郑州濮阳廊坊邢台大同太原南昌九江
    java.util.stream.ReferencePipeline$Head@21588809
    java.util.stream.ReferencePipeline$Head@2aae9190
    java.util.stream.ReferencePipeline$Head@2f333739
    java.util.stream.ReferencePipeline$Head@77468bd9
    郑州濮阳廊坊邢台大同太原南昌九江
    

    可以看到使用map如果和flatMap写法一样强行获取流进行打印,打印的是流对象的信息,而不是流对象中的集合信息。

    4.使用多次flatMap

    flatMap也可以使用多次,则会把更深一层的集合流中的数据在外层进行处理

    在上面的案例中,我们假如再添加一个用户类 用户类中包含地址类集合

    数据结构

    2.jpg

    用户类

    public class User {
        private String name;
        private List<Address> addressList;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public List<Address> getAddressList() {
            return addressList;
        }
    
        public void setAddressList(List<Address> addressList) {
            this.addressList = addressList;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", addressList=" + addressList +
                    '}';
        }
    }
    

    测试案例

        public static void main(String[] args) {
    
            List<String> cityListOne = new ArrayList<>();
            cityListOne.add("郑州");
            cityListOne.add("濮阳");
            List<String> cityListTwo = new ArrayList<>();
            cityListTwo.add("廊坊");
            cityListTwo.add("邢台");
            List<String> cityListThree = new ArrayList<>();
            cityListThree.add("大同");
            cityListThree.add("太原");
            List<String> cityListFour = new ArrayList<>();
            cityListFour.add("南昌");
            cityListFour.add("九江");
    
            Address addressOne = new Address();
            addressOne.setProvince("河南");
            addressOne.setCityList(cityListOne);
    
            Address addressTwo = new Address();
            addressTwo.setProvince("河北");
            addressTwo.setCityList(cityListTwo);
    
            Address addressThree = new Address();
            addressThree.setProvince("山西");
            addressThree.setCityList(cityListThree);
    
            Address addressFour = new Address();
            addressFour.setProvince("江西");
            addressFour.setCityList(cityListFour);
    
            List<Address> addresseListOne = new ArrayList<>();
            addresseListOne.add(addressOne);
            addresseListOne.add(addressTwo);
            List<Address> addresseListTwo = new ArrayList<>();
            addresseListTwo.add(addressThree);
            addresseListTwo.add(addressFour);
    
            //新增用户来包含地址集合
            List<User> userList = new ArrayList<>();
            User u1 = new User();
            u1.setName("张三");
            u1.setAddressList(addresseListOne);
    
            User u2 = new User();
            u2.setName("李四");
            u2.setAddressList(addresseListTwo);
    
            userList.add(u1);
            userList.add(u2);
    
    
    
            //使用map输出所有的城市名称
            userList.stream()
                    .map(u->u.getAddressList())
                    .forEach(addressList->{
                        addressList.forEach(address -> {
                            address.getCityList().forEach(city->{
                                System.out.print(city);
                            });
                        });
                    });
    
            System.out.println("");//换行
            //使用flatMap输出所有城市名称
            userList.stream()
                    .flatMap(u -> u.getAddressList().stream())
                    .flatMap(a -> a.getCityList().stream())
                    .forEach(city -> System.out.print(city));
    
    
        }
    

    打印结果

    郑州濮阳廊坊邢台大同太原南昌九江
    郑州濮阳廊坊邢台大同太原南昌九江
    

    可以看出flatMap可以使用多次将更深一层的集合流中的数据拿到外层进行处理。而使用map则相当繁琐


    以上就是我对java8中mapflatMap的理解

    相关文章

      网友评论

        本文标题:java8中map和flatMap区别

        本文链接:https://www.haomeiwen.com/subject/awdxrctx.html