Stream.of(a, b, c).parallel().map(Object::toString).iterator();
返回的迭代器是否保证按顺序提供值2,3,4?
我知道toArray()和collect()保证集合的值正确。另外,我并没有问如何从迭代器创建流。
答案 0 :(得分:7)
这是规范中的疏忽。如果流具有已定义的遭遇顺序,则意图是其Iterator按照遭遇顺序生成元素。如果流没有定义的遭遇顺序,迭代器当然会以某种顺序生成元素,但该顺序不会被定义。
我已提交错误JDK-8194952来跟踪对规范的更改。
看起来其他人已经浏览了足够多的实现,以表明它确实会产生遇到顺序的元素。此外,我们的流测试依赖于此属性。例如,toList
收集器的测试断言列表中的元素的顺序与从流的迭代器中获得的顺序相同。因此,即使它尚未正式指定(即),您可能也可以安全地依赖此行为。
答案 1 :(得分:3)
用于从其他非关联值创建流的Stream.of
method返回一个顺序的有序流。
返回一个顺序排序的流,其元素是指定的值。
根据package Javadocs for java.util.stream
,副作用部分:
IntStream.range(0,5).parallel().map(x -> x*2).toArray()
必须生成[0, 2, 4, 6, 8]
这意味着parallel()
和map()
会保留流是顺序/有序的。
我已跟踪Stream
Stream.of
为ReferencePipeline
类创建的@Override
public final Iterator<P_OUT> iterator() {
return Spliterators.iterator(spliterator());
}
的实现。
iterator()
该实施的Iterator
方法推迟到Spliterator.iterator()
,其代码只需依靠Spliterator
&#39; {{}适用于tryAdvance
界面{1}}方法,并且不会更改任何流特征:
public static<T> Iterator<T> iterator(Spliterator<? extends T>
spliterator) {
Objects.requireNonNull(spliterator);
class Adapter implements Iterator<T>, Consumer<T> {
boolean valueReady = false;
T nextElement;
@Override
public void accept(T t) {
valueReady = true;
nextElement = t;
}
@Override
public boolean hasNext() {
if (!valueReady)
spliterator.tryAdvance(this);
return valueReady;
}
@Override
public T next() {
if (!valueReady && !hasNext())
throw new NoSuchElementException();
else {
valueReady = false;
return nextElement;
}
}
}
return new Adapter();
}
总之,是的,订单得到保证,因为Stream.of
创建了一个&#34;顺序排序的流&#34;,而没有您在上面使用的任何操作:parallel
,{{1} },或map
更改特征。实际上,iterator
使用基础流iterator
来迭代流元素。
答案 2 :(得分:1)
我到目前为止最接近保证的是package documentaion for java.util.stream中的以下陈述:
除了标识为显式非确定性的操作(例如findAny())之外,流是顺序执行还是并行执行不应更改计算结果。
可以说,iterator()
以不同的顺序生成Iterator
迭代将是结果&#34;的变化,就像生成包含List
元素一样多不同的顺序是collect()
。
答案 3 :(得分:0)
是的,它会。这是因为终端操作除非在文档(例如forEach
中另有说明 - 明确指定这是非确定性vs forEachOrdered
)中另有规定,否则它们会保留遭遇顺序。您的Stream.of
确实会返回订购的流;在任何地方都没有破坏的订单(例如,通过unordered
或sorted/distinct
)
答案 4 :(得分:0)
鉴于Stream.of返回的事实,文档中所述的有序流以及您显示的所有中间操作都没有改变这种行为,因此我们可以说返回的iterator
是保证在枚举时按顺序提供值2, 3, 4
,因为在有序流或序列(例如List实现)上调用iterator
终端操作应该在枚举时按顺序生成元素。
因此,只要我们有一个有序的源,中间操作和&amp;成功,代码是顺序执行还是并行执行都无关紧要。尊重这个订单的终端操作然后应该保持订单。