[英]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
循環。 我不會涵蓋Stream
, Spliterator
和collect()
如何工作的完整邏輯。 如果您需要更多詳細信息,請在網上搜索。
因此,必須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.