【问题标题】:Java 8 Stream ExecutionJava 8 流执行
【发布时间】:2018-08-01 06:39:12
【问题描述】:

你能解释一下下面代码的执行过程吗?主要是sorted方法。

Stream.of("d2", "a2", "b1", "b3", "c")
    .sorted((s1, s2) -> {
        System.out.printf("sort: %s; %s\n", s1, s2);
        return s1.compareTo(s2);
    })
    .filter(s -> {
        System.out.println("filter: " + s);
        return s.startsWith("a");
    })
    .map(s -> {
        System.out.println("map: " + s);
        return s.toUpperCase();
    })
    .forEach(s -> System.out.println("forEach: " + s));

输出:

sort:    a2; d2
sort:    b1; a2
sort:    b1; d2
sort:    b1; a2
sort:    b3; b1
sort:    b3; d2
sort:    c; b3
sort:    c; d2
filter:  a2
map:     a2
forEach: A2
filter:  b1
filter:  b3
filter:  c
filter:  d2

谢谢,参考:https://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/

【问题讨论】:

  • 您有什么具体问题吗?

标签: java java-8 java-stream


【解决方案1】:

所以Java8 试图通过对任何给定输入尽快执行所有高阶函数来加快执行速度。也就是说,例如,如果您在列表中连续调用两次map,那么它将只访问列表中的每个元素一次。这加快了速度,因为它从 2 次通过列表变为 1 次。举个简单的例子来说明:

Stream.of(1, 2, 3)
    .map(s -> {
        System.out.println("map: " + s.toString());
        return s;
    })
    .map(s -> {
        System.out.println("map: " + s.toString());
        return s;
    })

这将打印:

1
1
2
2
3
3

因为对于maps 来说,“触摸”列表中的每个元素一次比完全遍历列表要快!

就你的例子来说,让我们一块一块地看:

sort:    a2; d2
sort:    b1; a2
sort:    b1; d2
sort:    b1; a2
sort:    b3; b1
sort:    b3; d2
sort:    c; b3
sort:    c; d2

所有的排序都需要同时发生,而且都需要先发生。这是因为计算机在排序完成之前无法知道哪个元素将在哪个位置(即它不能在同一列表位置进行两次映射,因为排序可能会改变这一点)

接下来,你基本上有这个:

Stream.of("a2", "b1", "b3", "c", "d2")
    .filter(s -> {
        System.out.println("filter: " + s);
        return s.startsWith("a");
     })
    .map(s -> {
        System.out.println("map: " + s);
        return s.toUpperCase();
    })
    .forEach(s -> System.out.println("forEach: " + s));

现在,为了尽量减少通过列表的次数,Java 将遍历列表中的每个元素并执行filter,然后是map,然后是forEach。这是因为这些都不依赖于元素的位置。换句话说,Java 认为它可以对每个元素执行所有这些操作,而不是为每个函数遍历整个列表三次!

现在:

filter:  a2
map:     a2
forEach: A2

我们filter第一个元素,然后我们map覆盖它,然后我们做最后的forEach打印。

filter:  b1
filter:  b3
filter:  c
filter:  d2

这些都被过滤掉了,所以其余的函数不会被调用!

【讨论】:

    【解决方案2】:

    您似乎对为什么输出中连续有几个排序调用感到困惑。

    让我们解释一下;首先,中间操作分为filtermap无状态有状态,例如sorteddistinct 等人

    正如 Brian Goetz here under Executing a stream pipeline 所提到的:

    无状态操作是可以对元素执行的操作 在不知道任何其他元素的情况下。例如,一个 过滤操作只需要检查当前元素即可 确定是包含还是消除,不过是排序操作 必须先查看所有元素,然后才能知道首先发出哪个元素

    强调我的。

    排序操作必须在将给定元素发送到下一个操作之前查看所有元素这一事实是您在输出中连续看到多个排序调用的原因。


    此外,您可能还想阅读are Java streams stages sequential? 这在一定程度上源于sorted 操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多