如何从Java 8 Streams中获取forEach循环的列表输出

时间:2018-05-31 06:34:42

标签: java java-8 java-stream

我有两个不同的相同对象列表,但属性不同,并且在这些对象中有一个公共标识符。我想迭代第一个列表并从第二个列表中获取相应的对象(具有公共属性),然后将这些对象包装起来,最后使用Java Streams将该对象添加到列表中。

这是我采取的例子。

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

现在,在主类中,我将创建两个列表实例,如此

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

并按以下方式添加对象

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

现在,我想迭代jrList并在srList(同名)中找到相应的Person对象。然后我将这些对象包装为PersonWrapper并将该对象包装到列表中。

到目前为止,这就是我一直在做的事情

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

现在,我想知道如何将Collectors.toList()替换为wrapperList,或将Collectors.toList()的输出添加到wrapperList

请帮助我实现这一目标。

3 个答案:

答案 0 :(得分:12)

而不是使用forEach而只是从头开始使用流:

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

通过使用flatMap,您可以}流(<{1}})压缩为单个流(Stream<Stream<PersonWrapper>>

如果你不能自己实例化Stream<PersonWrapper>或者真的需要附加它。您可以将以上代码段更改为以下内容:

wrapperList

答案 1 :(得分:3)

虽然Lino's回答肯定是正确的。我认为,如果jrList中的某个人物对象只能在seniorList最多只有一个相应的匹配,换句话说,如果它是1-1关系,那么你可以改进Lino通过查找第一个匹配项给出的解决方案如下:

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

或如果无法保证jrList中的每个人都会在seniorList中找到相应的匹配项,那么请将上述查询更改为:

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

不同之处在于,现在我们不会在get()的结果上调用findFirst(),而是在orElse无法找到相应值的情况下提供findFirst的默认值,然后我们filter null值在随后的中间操作中输出,因为它们不需要。

答案 2 :(得分:-1)

用下面的代码替换你的循环逻辑。

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