Comparison and use cases of map and flatMap in Java~stream processing

Preface

Using Java8's new feature Stream streaming processing can improve the efficiency of some operations on collections, combined with lambda expressions, can simplify the code to the extreme, especially the parallel stream, you can learn about it, and it can still be used in some occasions. It is efficient, and it is not troublesome to code.

And the core of streaming processing is a shallow copy and reference pipeline, which internally implements a reference pipeline ReferencePipeline, which copies the references of the data that needs to be processed, then processes the data, and finally collects the results and puts these references in another. In a collection.

Today I’m going to talk about the comparison and use of map and flatMap in stream processing.

Similarities and differences

First look at the source code

    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    
    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

Common ground

  • All rely on stream for conversion, combined with lambda input and return value, convert one type into another type based on program logic.
  • The final result returned is still a stream, and it can also be continuously streamed or collected.

the difference

  • The method parameters are different. The first parameter is the same, but the second is different. There is no requirement for the second parameter of the map, but when using flatMap, the second parameter has to be received with a stream.
  • So flatMap is mostly used in many-to-many, one-to-many, that is, map is to map a data node in a data stream to another data node, and flatMap is to map a data node in a data stream to another data Stream, this other data stream can be one data node or multiple data nodes.
  • Flatmap can be either single conversion or one-to-many/many-to-many conversion. Flatmap requires the return of Observable, so it can carry out from/just event distribution again internally, and take out single objects one by one (the ability to convert objects is different)

Use Cases

For example, we use map to map a per object to a string object

    static class Per {
    
    
        public String name;
        public int age;

        public Per(String name, int age) {
    
    
            this.name = name;
            this.age = age;
        }

        public String getName() {
    
    
            return name;
        }

        public void setName(String name) {
    
    
            this.name = name;
        }

        public int getAge() {
    
    
            return age;
        }

        public void setAge(int age) {
    
    
            this.age = age;
        }

        @Override
        public String toString() {
    
    
            return "Per{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

    public static void main(String[] args) {
    
    
        List<Per> list = new ArrayList<>();
        list.add(new Per("listen", 22));
        list.add(new Per("bike", 24));
        list.add(new Per("milk", 27));

        List<String> collect = list.stream().map(Per::toString).collect(Collectors.toList());

        System.out.println(list);
        System.out.println("---");
        System.out.println(collect);

    }

One-to-one can be achieved, so what we need, suppose a per person has multiple children, and we want to get these multiple children, can it be achieved using map? For example, the following code.

    static class Child {
    
    
        public String name;
        public int age;

        public Child(String name, int age) {
    
    
            this.name = name;
            this.age = age;
        }
                @Override
        public String toString() {
    
    
            return "Child{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

    static class Per {
    
    
        public String name;
        public int age;
        public Child[] Children;

        public Per(String name, int age) {
    
    
            this.name = name;
            this.age = age;
        }

        public Child[] getChildren() {
    
    
            return Children;
        }

        public void setChildren(Child[] children) {
    
    
            Children = children;
        }

        public String getName() {
    
    
            return name;
        }

        public void setName(String name) {
    
    
            this.name = name;
        }

        public int getAge() {
    
    
            return age;
        }

        public void setAge(int age) {
    
    
            this.age = age;
        }

        @Override
        public String toString() {
    
    
            return "Per{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

At this time, note that there are multiple children, and we are using array storage. If we still use map at this time, we can only accept the array of children of each per, not each child as we wish.

    public static void main(String[] args) {
    
    
        List<Per> list = new ArrayList<>();
        Per per1 = new Per("Listen", 22);
        per1.setChildren(new Child[] {
    
    new Child("a", 1), new Child("b", 2)});
        Per per2 = new Per("Milk", 26);
        per2.setChildren(new Child[] {
    
    new Child("c", 1), new Child("d", 2)});
        list.add(per1);
        list.add(per2);

        List<Child[]> collect = list.stream().map(Per::getChildren).collect(Collectors.toList());
        collect.forEach(item -> System.out.println(Arrays.toString(item)));
    }

It can be achieved using flatMap.

    public static void main(String[] args) {
    
    
        List<Per> list = new ArrayList<>();
        Per per1 = new Per("Listen", 22);
        per1.setChildren(new Child[] {
    
    new Child("a", 1), new Child("b", 2)});
        Per per2 = new Per("Milk", 26);
        per2.setChildren(new Child[] {
    
    new Child("c", 1), new Child("d", 2)});
        list.add(per1);
        list.add(per2);

        List<Child> collect = list.stream().flatMap(item -> Arrays.stream(item.getChildren())).collect(Collectors.toList());
        System.out.println(collect);

    }

Guess you like

Origin blog.csdn.net/Shangxingya/article/details/115033235