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