实际上,原始问题中嵌入了几个关于排序的问题。
Holger 的回答涵盖了管道中流操作的顺序。对于特定的流元素,必须按照程序中的说明执行管道操作,因为一般情况下,类型必须匹配,并且因为以任何其他方式执行它都没有任何意义。从原始示例开始,流库无法重新排序操作,就好像它们已被编写一样,
List<String> modified = list.parallelStream()
.filter(s -> !s.equals("b-b")) // these two operations are swapped
.map(s -> s + "-" + s) // compared to the original example
.map(s -> s.substring(2))
.collect(toList());
因为那么结果将是 [a, b, c]。这不会发生。
最初的问题询问答案是否可以是 [c, a] 而不是 [a, c]。这实际上是关于另一种排序的问题,我们称之为遇到顺序。java.util.stream 包文档中提到了这个概念。不幸的是,我所知道的任何地方都没有明确定义它。简而言之,它与流中元素的相对定位(与执行顺序相反)以及这种定位是否具有任何语义有关。
例如,考虑来自 HashSet 和 ArrayList 的流。基于 HashSet 的流没有定义的遇到顺序,或者换句话说,它是无序的。如果您将一堆元素放入 HashSet 中,然后将它们迭代出来,它们将以某种可能与您放入它们的顺序无关的顺序出现。
但是,基于列表的流确实具有定义的遇到顺序。在原始示例中,列表是 [a, b, c],显然“a”在“b”之前,“b”在“c”之前。这种定位通常由从源到输出的流操作保留。
让我修改原来的例子来说明遭遇顺序的意义。我所做的只是更改原始列表中字符串的顺序:
List<String> list = Arrays.asList("c", "b", "a");
List<String> modified = list.parallelStream()
.map(s -> s + "-" + s) //"c-c", "b-b", "a-a"
.filter(s -> !s.equals("b-b")) //"c-c", "a-a"
.map(s -> s.substring(2)) //"c", "a"
.collect(toList());
正如我们所料,输出是 [c, a]。现在让我们在集合而不是列表上运行流:
List<String> list = Arrays.asList("c", "b", "a");
Set<String> set = new HashSet<>(list);
List<String> modified = set.parallelStream()
.map(s -> s + "-" + s)
.filter(s -> !s.equals("b-b"))
.map(s -> s.substring(2))
.collect(toList());
这一次,结果是 [a, c]。管道操作(map 、filter、map)没有改变顺序,但是由于集合中元素的遇到顺序是未定义的,结果最终以某种与先前结果不同的顺序出现在目标列表中。
(我不得不更改原始列表中值的顺序,因为碰巧 HashSet 的迭代顺序与元素的哈希码有关,而这里给出的简单字符串示例具有连续的哈希码。)
还有另一种“排序”可以考虑,它是不同元素之间管道操作的相对执行顺序。对于并行流,这是完全不确定的。观察这一点的一种方法是从管道操作中改变对象。(为了安全地做到这一点,被变异的对象当然必须是线程安全的,依赖任何此类副作用的顺序是不明智的。)这是一个例子:
List<Integer> list1 = Collections.synchronizedList(new ArrayList<>());
List<Integer> list2 =
IntStream.range(0, 10)
.parallel()
.boxed()
.peek(i -> list1.add(i))
.collect(toList());
System.out.println(list1);
System.out.println(list2);
在我的系统上,输出是:
[5, 6, 2, 3, 4, 8, 9, 7, 0, 1]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
源的遇到顺序被保留到list2中的输出,但是list1的顺序一般是不同的。实际上,元素的顺序list1
因运行而异,而元素的顺序list2
始终相同。
总之,这里显示了三种不同的排序方式:
- 对某些特定元素的管道操作的排序;
- 流的相遇顺序,和
- 管道操作在不同元素上的执行顺序。
他们都是不同的。