【JDK特性】stream 里面的map和flatMap区别

背景

JDK8中, stream流程 下的map 就不多说了,很熟悉,flatmap倒是不是特别熟悉,




map 和 flatMap 的区别

看一个例子:

   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> addresses = new ArrayList<>();
   addresses.add(addressOne);
   addresses.add(addressTwo);
   addresses.add(addressThree);
   addresses.add(addressFour);

   //使用map输出所有的城市名称
   addresses.stream()
           .map(address -> address.getCityList())
           .forEach(cityList ->
                   cityList.forEach(city -> System.out.print(city + " "))
           );

   System.out.println("");
   //使用flatMap输出所有城市名称
   addresses.stream()
           .flatMap(address -> address.getCityList().stream())
           .forEach(city -> System.out.print(city + " "));
}


这里可以看到使用 flatMap 也是返回一个 stream流
看到源码也知一二,看到 map 和 flatmap 对于里面的函数式的差异:

@Override
@SuppressWarnings("unchecked")
public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
    Objects.requireNonNull(mapper);
    return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
                                 StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
        @Override
        Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
            return new Sink.ChainedReference<P_OUT, R>(sink) {
                @Override
                public void accept(P_OUT u) {
                    downstream.accept(mapper.apply(u));
                }
            };
        }
    };
}


@Override
public final <R> Stream<R> flatMap(Function<? super P_OUT, ? extends Stream<? extends R>> mapper) {
    Objects.requireNonNull(mapper);
    // We can do better than this, by polling cancellationRequested when stream is infinite
    return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
                                 StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
        @Override
        Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
            return new Sink.ChainedReference<P_OUT, R>(sink) {
                @Override
                public void begin(long size) {
                    downstream.begin(-1);
                }

                @Override
                public void accept(P_OUT u) {
                    try (Stream<? extends R> result = mapper.apply(u)) {
                        // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
                        if (result != null)
                            result.sequential().forEach(downstream);
                    }
                }
            };
        }
    };
}

嗯,怎么说呢。flalmap 还可以:使用多次

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则相当繁琐

就此,如果再遇遍历,可多尝试用一下 flapMap。

完。


参考:
java8中map和flatMap区别 (本文的例子均参考的这里,并且例子说得更好一些)

posted @ 2023-02-19 12:39  aaacarrot  阅读(176)  评论(0编辑  收藏  举报