簡體   English   中英

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

[英]Do java8 Stream's filter() and map() method use iterations?

我在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;    
    }
}

然后我有一個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;
    }
}  

我想知道:

1> filter()map()內部是否使用循環迭代List people中的所有Person對象?

2>如果是,它們是否會在列表中的兩個不同時間循環遍歷所有對象(第一次迭代由filter()而另一次迭代由map() )?

3>如果是,再次,如果我添加另一個map()filter()方法,它是否會第三次循環遍歷所有對象?

4>如果是,那么它與傳統的命令式樣式編碼有什么不同的性能(實際上,在傳統的命令式樣式中,我們可以在大多數時間內在單個循環中完成所有過濾和映射。所以性能明智,在這種情況下,命令式樣式編碼比流更好。)?

PS:如果上述任何問題都有“ No ,請添加有關事情如何運作的說明。

還有一點:內部流完成的迭代和我們以命令式風格進行的迭代是否存在差異? 請詳細解釋一下我的知識。

首先,您的代碼無法編譯,因為map()返回Stream而不是List 您必須使用終端操作結束流鏈, filter()map()都是中間操作 在javadoc說得那么正確。 在您的情況下,您需要添加.collect(Collectors.toList())以使其編譯並運行正常。

1> filter()map()內部是否使用循環迭代List人員中的所有Person對象?

不。終端操作正在進行循環。

由於問題2到4假定答案Yes ,因此他們沒有答案。

如果上述任何問題都是“ No ,請添加有關事情如何運作的說明。

閱讀文檔 ,或搜索網絡。 這很好解釋。

流內部的迭代和我們在命令式樣式中進行的迭代是否存在差異?

是的,例如,流可以利用並行線程執行。 即使是單線程,整個操作的工作方式也有所不同,盡管從邏輯上講,它們在高級別上基本相同。


在您的代碼中,添加了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調用將迭代,因此組合起來它們等同於for循環。 我不會涵蓋StreamSpliteratorcollect()如何工作的完整邏輯。 如果您需要更多詳細信息,請在網上搜索。

因此,必須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