How to get a list output from forEach loop in Java 8 Streams

Ravi :

I have two different lists of same objects but different properties and with a common identifier in those objects. I would like to iterate over the first list and get the corresponding object from the second (which has common properties) and then wrap those objects around and finally add that object to a list using Java Streams.

This is the example I have taken.

private class Person {
        private String name;
        private boolean isSenior;

        private Person(String name, boolean isSenior) {
            this.name = name;
            this.isSenior = isSenior;
        }

        public String getName() {
            return name;
        }

        public boolean isSenior() {
            return isSenior;
        }

        @Override
        public String toString() {
            return name + ": " + isSenior;
        }
    }

    private class PersonWrapper {
        private Person jrPerson;
        private Person srPerson;

        private PersonWrapper(Person jrPerson, Person srPerson) {
            this.jrPerson = jrPerson;
            this.srPerson = srPerson;
        }

        public Person getJrPerson() {
            return jrPerson;
        }

        public Person getSrPerson() {
            return srPerson;
        }

        @Override
        public String toString() {
            return jrPerson.toString() + "-" + srPerson.toString();
        }
    }

Now, in the main class, I will create two list instances like this

List<Person> jrPersons = new ArrayList<>();
List<Person> srPersons = new ArrayList<>();

and add the objects in the following manner

jrList.add(new Person("John", false));
jrList.add(new Person("Paul", false));
jrList.add(new Person("Mike", false));

seniorList.add(new Person("John", true));
seniorList.add(new Person("Paul", true));
seniorList.add(new Person("Mike", true));

Now, I want to iterate over the jrList and find the corresponding Person object in the srList (same name). Then I would wrap these objects as PersonWrapper and that object to a list.

So far, this is what I have been doing

List<PersonWrapper> wrapperList = new ArrayList<>();

jrList.forEach(jr -> seniorList.stream().filter(sr -> jr.getName().equals(sr.getName())).map(sr -> new PersonWrapper(jr, sr)).collect(Collectors.toList()));

Now, I would like to know how the Collectors.toList() can be substituted by wrapperList or how the output from Collectors.toList() be added to wrapperList.

Please help me in achieving this.

Ousmane D. :

While Lino's answer is certainly correct. I would argue that if a given person object in jrList can only ever have one corresponding match in seniorList maximum, in other words, if it's a 1-1 relationship then you can improve upon the solution given by Lino by finding the first match as follows:

List<PersonWrapper> resultSet = jrList.stream()
                .map(p -> seniorList.stream()
                        .filter(sr -> p.getName().equals(sr.getName()))
                        .findFirst()
                        .map(q -> new PersonWrapper(p, q))
                        .get())
                .collect(Collectors.toList());

or if there is no guarantee that each person in jrList will have a corresponding match in seniorList then change the above query to:

List<PersonWrapper> resultSet = jrList.stream()
                .map(p -> seniorList.stream()
                        .filter(sr -> p.getName().equals(sr.getName()))
                        .findFirst()
                        .map(q -> new PersonWrapper(p, q))
                        .orElse(null))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

The difference is that now instead of calling get() on the result of findFirst() we provide a default with orElse in case findFirst cannot find the corresponding value and then we filter the null values out in the subsequent intermediate operation as they are not needed.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=459122&siteId=1