假设我有这个简单的程序
List<String> input = Arrays.asList("1", "2", "3");
List<String> result = input.stream()
.map(x -> x + " " + x)
.filter(y -> !y.startsWith("1"))
.collect(Collectors.toList());
在幕后,它是像 a) 还是 b) 一样工作
一个
map
"1" + " " + "1"
"2" + " " + "2"
"3" + " " + "3"
filter
"1 1" does not begin with "1"? = false
"2 2" does not begin with "1"? = true
"3 3" does not begin with "1"? = true
collect
add "2 2" to list
add "3 3" to list
result = List("2 2", "3 3")
B
map
"1" + " " + "1"
filter
"1 1" does not begin with "1"? = false
map
"2" + " " + "2"
filter
"2 2" does not begin with "1"? = true
collect
add "2 2" to list
map
"3" + " " + "3"
filter
"3 3" does not begin with "1"? = true
collect
add "3 3" to list
result = List("2 2", "3 3")
最佳答案
它的工作方式与选项 B 类似,不一定完全按照那个顺序,但更重要的是它一次对一个元素执行所有操作。
这背后的原因是变量只通过流一次,所以当您现在拥有该元素时,您需要执行所有操作,因为一旦元素通过,它就永远消失了(从流的角度)。
在线性设置中,您的代码非常非常粗略地等同于以下代码,这是一个非常简化的版本,但我希望您明白这一点:
Collection<String> input = Arrays.asList("1", "2", "3");
Function<String, String> mapper = x -> x + " " + x;
Predicate<String> filter = y -> !y.startsWith("1");
Collector<String, ?, List<String>> toList = Collectors.toList();
List<String> list = ((Supplier<List<String>>)toList.supplier()).get();
for (String in : input) {
in = mapper.apply(in);
if (filter.test(in)) {
((BiConsumer<List<String>, String>)toList.accumulator()).accept(list, in);
}
}
你在这里看到的是:
- 作为输入
Collection<String>
,您的输入。 - A
Function<String, String>
匹配您的map()
. - A
Predciate<String>
匹配您的filter()
. - A
Collector<String, ?, List<String>>
匹配您的collect()
,这是一个对String
类型的元素进行操作的收集器, 使用中间存储?
并给出List<String>
.
然后它做的是:
- 从收集器的供应商(类型:
Supplier<List<String>>
)处获取新列表。 - 循环遍历输入的每个元素,在对
Stream<String>
进行操作时在内部完成,我正在使用Collection<String>
这里是为了明确,这样我们仍然可以连接到旧的 Java 7 世界。 - 应用您的映射函数。
- 测试您的过滤谓词。
- 获取
BiConsumer<List<String>, String>
的累加器(类型:toList
)收集器,这是将List<String>
作为参数的二进制消费者它已经有了,String
它想添加。 - 喂我们的
list
和in
到蓄能器。
请非常小心地注意,实际的实现要先进得多,因为操作可以按任何顺序发生,也可以发生多个,等等。
关于Java 8 流 - 链中的每个步骤都针对整个输入进行评估,还是项目通过?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22736122/