web-dev-qa-db-fra.com

Comment obtenir une sortie de liste à partir de la boucle forEach dans Java 8 Streams

J'ai deux listes différentes de mêmes objets mais de propriétés différentes et avec un identifiant commun dans ces objets. Je voudrais parcourir la première liste et obtenir l'objet correspondant de la seconde (qui a des propriétés communes), puis encapsuler ces objets et enfin ajouter cet objet à une liste en utilisant Java Streams.

Voici l'exemple que j'ai pris.

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();
        }
    }

Maintenant, dans la classe principale, je vais créer deux instances de liste comme celle-ci

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

et ajoutez les objets de la manière suivante

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));

Maintenant, je veux parcourir la jrList et trouver l'objet Person correspondant dans la srList (même nom). Ensuite, j'emballerais ces objets en tant que PersonWrapper et cet objet dans une liste.

Jusqu'à présent, c'est ce que j'ai fait

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()));

Maintenant, je voudrais savoir comment la Collectors.toList() peut être remplacée par wrapperList ou comment la sortie de Collectors.toList() peut être ajoutée à wrapperList.

Veuillez m'aider à y parvenir.

7
Ravi

Alors que Lino's la réponse est certainement correcte. Je dirais que si un objet personne donné dans jrList ne peut avoir qu'une seule correspondance correspondante dans seniorList maximum, en d'autres termes, s'il s'agit d'une relation 1-1, vous pouvez améliorer la solution donné par Lino en trouvant la première correspondance comme suit:

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());

ou s'il n'y a aucune garantie que chaque personne dans jrList aura une correspondance correspondante dans seniorList, remplacez la requête ci-dessus par:

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());

La différence est que maintenant au lieu d'appeler get() sur le résultat de findFirst() nous fournissons une valeur par défaut avec orElse au cas où findFirst ne trouverait pas la valeur correspondante puis nous filter les null valeurs dans l'opération intermédiaire suivante car elles ne sont pas nécessaires.

4
Ousmane D.

Au lieu d'utiliser un forEach utilisez simplement des flux depuis le début:

List<PersonWrapper> wrapperList = jrList.stream()
    .flatMap(jr -> seniorList.stream()
         .filter(sr -> jr.getName().equals(sr.getName()))
         .map(sr -> new PersonWrapper(jr, sr))
    )
    .collect(Collectors.toList());

En utilisant flatMap, vous pouvez aplatir un flux de flux (Stream<Stream<PersonWrapper>>) en un seul flux (Stream<PersonWrapper>)

Si vous ne pouvez pas instancier wrapperList par vous-même ou si vous devez vraiment y ajouter. Vous pouvez modifier l'extrait ci-dessus comme suit:

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

jrList.stream()
    .flatMap(jr -> seniorList.stream()
         .filter(sr -> jr.getName().equals(sr.getName()))
         .map(sr -> new PersonWrapper(jr, sr))
    )
    .forEach(wrapperList::add);
12
Lino