我在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;
}
}
文件中有一个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;
}
}
然后我有一个filter()
文件,它创建一个人员列表并使用流来过滤和打印列表中的内容:
map()
我想知道:
1&GT; Person
和List
内部使用循环来迭代people
filter()
中的所有map()
个对象吗?
2 - ;如果是,它们是否会在列表中的两个不同时间循环遍历所有对象(map()
的第一次迭代和filter()
的其他迭代)?
3&GT;如果是,如果我添加了另一个No
或{{1}}方法,它是否会再次循环遍历所有对象?
4&GT;如果是,那么它与传统的命令式样式编码有什么不同的性能(实际上,在传统的命令式样式中,我们可以在大多数时间内在单个循环中进行所有过滤和映射。因此性能明智,命令式在这种情况下,编码比流更好。)?
PS:如果上述任何问题都有{{1}},请添加有关事情如何运作的说明。
还有一个问题:内部流完成的迭代和我们以命令式方式进行的迭代是否存在差异?请详细解释一下我的知识。
答案 0 :(得分:10)
首先,您的代码无法编译,因为map()
会返回Stream
,而不是List
。您必须使用终端操作结束流链,filter()
和map()
都是intermediate operations。在javadoc说得那么正确。在您的情况下,您需要添加.collect(Collectors.toList())
以使其编译并运行正常。
1&GT;
filter()
和map()
内部使用循环来迭代Person
人中的所有List
个对象吗?
没有。终端操作正在进行循环。
由于问题2到4假设Yes
答案,他们没有答案。
如果上述任何问题都有
No
,请添加有关事情如何运作的说明。
阅读documentation,或搜索网络。这很好解释。
内部流完成的迭代和我们以命令式风格进行的迭代是否存在差异?
是的,例如流可以利用并行线程执行。即使是单线程,整个操作的工作方式也有所不同,尽管从逻辑上讲,它们在高级别上基本相同。
示例强>
在您的代码中,添加了collect()
调用后,等效的命令式代码将是:
List<String> names = new ArrayList<>();
for (Person person : people)
if (person.isAdult())
names.add(person.getName());
要比较流逻辑的作用,首先要定义传递给filter()
和map()
的lambda:
Predicate<Person> filter = person -> person.isAdult();
Function<Person, String> map = person -> person.getName();
然后通过调用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();
现在,stream()
调用基本上提供Iterator
(实际上是Spliterator
),collect
调用将迭代,因此组合它们等同于{{ 1}}循环。我不会涵盖for
,Stream
和Spliterator
如何运作的完整逻辑。如果您需要更多详细信息,请在网上搜索。
因此,上面的命令式collect()
循环变为:
for