java8 Stream的filter()和map()方法是否使用迭代?

时间:2017-01-14 20:21:07

标签: java java-8 iteration java-stream

我在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; PersonList内部使用循环来迭代people filter()中的所有map()个对象吗?

2 - ;如果是,它们是否会在列表中的两个不同时间循环遍历所有对象(map()的第一次迭代和filter()的其他迭代)?

3&GT;如果是,如果我添加了另一个No或{{1}}方法,它是否会再次循环遍历所有对象?

4&GT;如果是,那么它与传统的命令式样式编码有什么不同的性能(实际上,在传统的命令式样式中,我们可以在大多数时间内在单个循环中进行所有过滤和映射。因此性能明智,命令式在这种情况下,编码比流更好。)?

PS:如果上述任何问题都有{{1}},请添加有关事情如何运作的说明。

还有一个问题:内部流完成的迭代和我们以命令式方式进行的迭代是否存在差异?请详细解释一下我的知识。

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}}循环。我不会涵盖forStreamSpliterator如何运作的完整逻辑。如果您需要更多详细信息,请在网上搜索。

因此,上面的命令式collect()循环变为:

for