如何从 Java 8 Streams 中的 forEach 循环获取列表输出
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/50618049/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get a list output from forEach loop in Java 8 Streams
提问by 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.
我有两个不同的相同对象列表,但具有不同的属性,并且在这些对象中有一个共同的标识符。我想遍历第一个列表并从第二个列表(具有公共属性)获取相应的对象,然后将这些对象包装起来,最后使用 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.
现在,我想遍历 jrList 并在 srList(同名)中找到相应的 Person 对象。然后我会将这些对象包装PersonWrapper
成一个列表。
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
.
现在,我想知道如何Collectors.toList()
替换wrapperList
或如何将输出Collectors.toList()
添加到wrapperList
.
Please help me in achieving this.
请帮助我实现这一目标。
采纳答案by Ousmane D.
While Lino'sanswer 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 Linoby finding the first match as follows:
而Lino 的回答当然是正确的。我会争辩说,如果给定的人对象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());
or if there is no guarantee that each person in jrList
will have a corresponding match in seniorList
then change the above query to:
或者如果不能保证每个人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());
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.
不同之处在于,现在不是调用get()
结果,findFirst()
而是我们提供默认值,orElse
以防万一findFirst
找不到相应的值,然后我们在后续的中间操作中将不需要filter
的null
值输出。
回答by Lino
Instead of using a forEach
just use streams from the beginning:
而不是forEach
从一开始就使用 just use 流:
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());
By using flatMap
you can flattena stream of streams (Stream<Stream<PersonWrapper>>
) into a single stream (Stream<PersonWrapper>
)
通过使用,flatMap
您可以将流 ( )流平展Stream<Stream<PersonWrapper>>
为单个流 ( Stream<PersonWrapper>
)
If you can't instantiate wrapperList
by yourself or really need to append to it. You can alter above snippet to following:
如果你不能自己实例化wrapperList
或者真的需要附加到它。您可以将上述代码段更改为以下内容:
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);
回答by Dharita Chokshi
Replace your looping logic with below code.
用下面的代码替换你的循环逻辑。
jrList.forEach(jr -> seniorList.stream().filter(sr -> jr.getName().equals(sr.getName()))
.map(sr -> wrapperList.add(new PersonWrapper(jr, sr))).collect(Collectors.toList()));