10

我有以下代码:

Set<Integer> l = new TreeSet<>();
l.add(1);
l.add(10);
l.add(3);
l.add(-3);
l.add(-4);

我想通过以下方式对集合进行排序:

l.stream().unordered().forEach(System.out::println);

forEach返回总是订购的集合!

然后我对这里的以下句子还有另一个疑问:

对于顺序流,遇到顺序的存在与否不会影响性能,只会影响确定性。如果流是有序的,在相同的源上重复执行相同的流管道将产生相同的结果;如果没有排序,重复执行可能会产生不同的结果。

事实上,如果我在无序流上尝试此代码,结果总是相同的,并且永远不会产生不同的结果:

Arrays.stream( new int[]{8, -1, 3}).forEach(System.out::println);
Arrays.stream( new int[]{8, -1, 3}).forEach(System.out::println);

我真的不明白这个API部分......

4

2 回答 2

18

unordered()操作不执行任何操作来显式地对流进行排序。它的作用是消除对流必须保持有序的约束,从而允许后续操作使用不必考虑排序的优化。

您可以在Java 8 文档中阅读相关内容:

对于顺序流,遇到顺序的存在与否不会影响性能,只会影响确定性。如果流是有序的,在相同的源上重复执行相同的流管道将产生相同的结果;如果没有排序,重复执行可能会产生不同的结果。
对于并行流,放宽排序约束有时可以提高执行效率。

...

在流具有遇到顺序但用户并不特别关心该遇到顺序的情况下,使用 unordered() 显式地对流进行降序可能会提高某些有状态或终端操作的并行性能。

于 2014-01-25T12:00:00.257 回答
11

您正在使用对元素进行排序的 TreeSet。因此,元素将是:

-4, -3, 1, 3, 10

使用串行流不会更改顺序,因此结果不依赖于有序/无序流的属性,正如您在第一个示例“串行流”中看到的(并且您自己也注意到了)。

l.stream().map(s->s+" ").forEach(System.out::print);

结果:-4 -3 1 3 10

l.stream().unordered().map(s->s+" ").forEach(System.out::print);

结果:-4 -3 1 3 10

如果使流并行,则可以创建多个线程并且不再保证结果,因为它取决于具体执行。另请注意,forEach() 不是有序操作,这意味着只要在其管道中有要处理的内容,它就会执行。请参阅示例“并行流上的无序操作”:

l.stream().parallel().map(s->s+" ").forEach(System.out::print);

结果:3 10 -3 1 -4

l.stream().unordered().map(s->s+" ").parallel().forEach(System.out::print);

结果:3 -4 -3 1 10

当您在并行流中使用有序操作(如 findFirst()、limit() 和 skip())时,情况会发生变化。当您在管道中使用 findFirst() 时,您真正想要的是拥有第一个元素,根据流中元素的顺序,您只是不想要任何元素,在这种情况下您将使用 findAny() . 要通过这些操作获得确定性结果,您将失去使用并行流的好处,因为必须将执行序列化以按特定顺序处理元素。

   l.stream().parallel().skip(2).limit(2).findFirst().ifPresent(System.out::print);

结果:1。无论您执行多少次代码,此结果将始终相同。

l.stream().unordered().parallel().skip(2).limit(2).findFirst().ifPresent(System.out::print);

结果:-3。每次执行代码时,此结果可能(或可能不会)改变,因为我们指定顺序并不重要。

这是完整的代码:

public static void main(String[] args) {
    Set<Integer> l = new TreeSet<>();
    l.add(1);
    l.add(10);
    l.add(3);
    l.add(-3);
    l.add(-4);

    System.out.println("Serial Stream");
    l.stream().map(s->s+" ").forEach(System.out::print);
    System.out.println();
    l.stream().unordered().map(s->s+" ").forEach(System.out::print);
    System.out.println("\n");

    System.out.println("Unordered Operations on a Parallel Stream");
    l.stream().parallel().map(s->s+" ").forEach(System.out::print);
    System.out.println();
    l.stream().unordered().map(s->s+" ").parallel().forEach(System.out::print);
    System.out.println("\n");

    System.out.println("Ordered Operations on a Parallel Stream");
    l.stream().parallel().skip(2).limit(2).findFirst().ifPresent(System.out::print);
    System.out.println();
    l.stream().unordered().parallel().skip(2).limit(2).findFirst().ifPresent(System.out::print);
    System.out.println("\n");

}

串行流

-4 -3 1 3 10

-4 -3 1 3 10

并行流上的无序操作

3 10 -3 -4 1

-3 1 3 10 -4

并行流上的有序操作

1

-3

于 2016-06-26T12:37:49.880 回答