简体   繁体   English

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

[英]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() and map() internally use a loop to iterate over all the Person objects in the List 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. 我不会涵盖StreamSpliteratorcollect()如何工作的完整逻辑。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM