8

说如果我有这个琐碎的程序

    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")

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")
4

2 回答 2

8

它的工作方式与选项 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);
    }
}

你在这里看到的是:

  • 作为输入 a Collection<String>您的输入。
  • 一个Function<String, String>匹配你的map().
  • 一个Predciate<String>匹配你的filter().
  • 一个Collector<String, ?, List<String>>匹配你的collect(),这是一个对类型元素进行操作的收集器String,使用中间存储?并给出一个List<String>.

然后它做的是:

  • 从收集器的供应商(类型:)处获取新列表Supplier<List<String>>
  • 循环输入的每个元素,在操作 a 时在内部完成Stream<String>,我在Collection<String>这里使用 a 来明确,这样我们仍然与旧的 Java 7 世界有联系。
  • 应用您的映射功能。
  • 测试您的过滤谓词。
  • 获取收集器的累加器(类型BiConsumer<List<String>, String>:)toList,这是二进制消费者,它以List<String>它已经拥有的作为参数,并且String它想要添加。
  • 将我们的listin喂给蓄能器。

请注意,真正的实现要先进得多,因为操作可以以任何顺序发生,并且可以发生多个,等等。

于 2014-03-29T20:01:49.717 回答
5

流的好处之一是中间操作的惰性求值。这意味着,当执行终端操作时,collect()在这种情况下,它会从先前的中间操作中请求一个元素 - filter(),然后从 中获取元素map(),然后对来自 的第一个元素进行操作list.stream()。所有元素都遵循相同的流程。所以是的,执行更像是选项 B。

另外,由于返回的收集器Collectors.toList()是有序的,所以保证了元素按顺序执行。在某些情况下,当UNORDERED为收集器设置 chararacteristic 时,评估可能会出现问题。

于 2014-03-29T20:03:40.987 回答