[英]Do java8 Stream's filter() and map() method use iterations?
I have a POJO
in Person.java
file: 我在Person.java
文件中有一个POJO
:
public class Person {
private String name;
private int age;
public Person(String n, int a) {
name = n;
age = a;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public boolean isAdult() {
return getAge() >= 18;
}
}
And then I have a Demo.java
file which creates a list of persons and uses streams to filter and print content from the list: 然后我有一个Demo.java
文件,它创建一个人员列表并使用流来过滤和打印列表中的内容:
import java.util.*;
public class Demo {
public static void main(String[] args) {
List<Person> people = createPeople();
List<String> names = people.stream()
.filter(person -> person.isAdult())
.map(person -> person.getName())
.collect(toList());
System.out.println(names);
}
private static List<Person> createPeople() {
List<Person> people = new ArrayList<>();
people.add("John", 19);
people.add("Joe", 21);
people.add("Jill", 16);
people.add("Sylvester", 18);
people.add("Hillary", 17);
people.add("Donald", 4);
return people;
}
}
I wanted to know: 我想知道:
1> Does filter()
and map()
internally use a loop to iterate over all the Person
objects in the List
people
? 1> filter()
和map()
内部是否使用循环迭代List
people
中的所有Person
对象?
2> If yes, do they loop over all the objects in the list two different times (1st iteration by filter()
and other by map()
)? 2>如果是,它们是否会在列表中的两个不同时间循环遍历所有对象(第一次迭代由filter()
而另一次迭代由map()
)?
3> If yes again, if I add another map()
or filter()
method, will it loop over all the objects again for the third time? 3>如果是,再次,如果我添加另一个map()
或filter()
方法,它是否会第三次循环遍历所有对象?
4> If yes again, then how is it different performance wise from our traditional imperative style coding (in-fact, in traditional imperative style, we could do all the filtering and mapping in 1 single loop most of the times. So performance wise, imperative style coding would perform better than streams in such a case.)? 4>如果是,那么它与传统的命令式样式编码有什么不同的性能(实际上,在传统的命令式样式中,我们可以在大多数时间内在单个循环中完成所有过滤和映射。所以性能明智,在这种情况下,命令式样式编码比流更好。)?
PS: If there is a No
to any of the above questions, please add an explanation regarding how things work then. PS:如果上述任何问题都有“ No
,请添加有关事情如何运作的说明。
One more: Is there a difference in iteration done by the stream internally and the iteration we do in imperative style? 还有一点:内部流完成的迭代和我们以命令式风格进行的迭代是否存在差异? Please shed some more light to my knowledge with some detailed explaination. 请详细解释一下我的知识。
First, your code doesn't compile, because map()
returns a Stream
, not a List
. 首先,您的代码无法编译,因为map()
返回Stream
而不是List
。 You must end the stream chain with a terminal operation, and both filter()
and map()
are intermediate operations . 您必须使用终端操作结束流链, filter()
和map()
都是中间操作 。 Says so right there in the javadoc. 在javadoc说得那么正确。 In your case, you need to add .collect(Collectors.toList())
to make it compile and run ok. 在您的情况下,您需要添加.collect(Collectors.toList())
以使其编译并运行正常。
1> Does
filter()
andmap()
internally use a loop to iterate over all thePerson
objects in theList
people? 1>filter()
和map()
内部是否使用循环迭代List
人员中的所有Person
对象?
No. The terminal operation is doing the looping. 不。终端操作正在进行循环。
Since questions 2 to 4 assumes a Yes
answer, they have no answer. 由于问题2到4假定答案Yes
,因此他们没有答案。
If there is a
No
to any of the above questions, please add an explanation regarding how things work then. 如果上述任何问题都是“No
,请添加有关事情如何运作的说明。
Read the documentation , or search the web. 阅读文档 ,或搜索网络。 It's pretty well explained. 这很好解释。
Is there a difference in iteration done by the stream internally and the iteration we do in imperative style? 流内部的迭代和我们在命令式样式中进行的迭代是否存在差异?
Yes, eg streams can utilize parallel thread execution. 是的,例如,流可以利用并行线程执行。 Even single-threaded there is a difference in how the entire operation works, though logically, at a high level, they are essentially the same. 即使是单线程,整个操作的工作方式也有所不同,尽管从逻辑上讲,它们在高级别上基本相同。
Example 例
In your code, with the collect()
call added, the equivalent imperative code would be: 在您的代码中,添加了collect()
调用,等效的命令式代码将是:
List<String> names = new ArrayList<>();
for (Person person : people)
if (person.isAdult())
names.add(person.getName());
To compare to what the stream logic does, first you define the lambdas passed to filter()
and map()
: 要比较流逻辑的作用,首先要定义传递给filter()
和map()
的lambda:
Predicate<Person> filter = person -> person.isAdult();
Function<Person, String> map = person -> person.getName();
Then you get the Collector
by calling Collectors.toList()
, and retrieve the objects it provide: 然后你会得到Collector
通过调用Collectors.toList()
并检索其提供的对象:
Collector<String, List<String>, List<String>> collector = (Collector) Collectors.toList();
Supplier<List<String>> supplier = collector.supplier();
BiConsumer<List<String>, String> accumulator = collector.accumulator();
Function<List<String>, List<String>> finisher = collector.finisher();
Now, the stream()
call basically provides an Iterator
(it's actually a Spliterator
) and the collect
call will iterate, so combined they are equivalent to the for
loop. 现在, stream()
调用基本上提供了一个Iterator
(它实际上是一个Spliterator
),并且collect
调用将迭代,因此组合起来它们等同于for
循环。 I won't cover the full logic of how Stream
, Spliterator
and collect()
works. 我不会涵盖Stream
, Spliterator
和collect()
如何工作的完整逻辑。 Search the web if you need more detail on that. 如果您需要更多详细信息,请在网上搜索。
So, the imperative for
loop above becomes: 因此,必须for
以上循环变为:
List<String> list = supplier.get(); // list = new ArrayList<>()
for (Person person : people) // collect() loop using Spliterator from stream()
if (filter.test(person)) { // if (person.isAdult())
String value = map.apply(person); // value = person.getName()
accumulator.accept(list, value); // list.add(value)
}
List<String> names = finisher.apply(list); // names = list
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.