Stream.of(a, b, c).parallel().map(Object::toString).iterator();
返回的迭代器是否保证以 a
、b
、c
的顺序提供值?
我知道 toArray()
和 collect()
保证了按正确顺序收集的集合。同时,我不是在询问如何从迭代器创建流。
Stream.of(a, b, c).parallel().map(Object::toString).iterator();
返回的迭代器是否保证以 a
、b
、c
的顺序提供值?
我知道 toArray()
和 collect()
保证了按正确顺序收集的集合。同时,我不是在询问如何从迭代器创建流。
toList
收集器的测试断言列表中的元素按与从流的迭代器获取的顺序相同的顺序出现。因此,即使尚未正式指定此行为,您可能可以放心依赖此行为。map
和 filter
也没有指定任何内容。或者只需添加一个明确的语句,说明操作保持遇到的顺序(如果有的话),除非另有说明。如果我们在这方面,对于有序流而言,max()
和 min()
在平局情况下返回第一个元素,例如 reduce((a,b)->a)
返回第一个元素,reduce((a,b)->b)
返回最后一个元素也仅仅是隐含的。而且,如果只有一个输入是无序的,则 Stream.concat
是无序的,例如 concat(range(0, 10), empty())
,这是显式的,但是这是一个可怕的决定... - HolgerStream.of
方法可用于从其他未关联的值创建流,返回一个顺序有序的流。
根据java.util.stream包的Javadocs中的副作用部分:返回一个其元素为指定值的顺序有序流。
这意味着
IntStream.range(0,5).parallel().map(x -> x*2).toArray()
必须产生[0, 2, 4, 6, 8]
parallel()
和map()
会保留流是否是顺序/有序的信息。Stream.of
创建的Stream
的实现到一个名为ReferencePipeline
的类。@Override
public final Iterator<P_OUT> iterator() {
return Spliterators.iterator(spliterator());
}
该实现的iterator()
方法调用Spliterator.iterator()
,其代码通过简单地依赖于Spliterator
的tryAdvance
方法来适配Iterator
接口,并且不会更改任何流特征:
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
创建了一个“顺序有序流”,而你上面使用的parallel
、map
或iterator
操作都不会改变这些特征。实际上,iterator
使用底层的Stream Spliterator
来迭代流元素。
iterator
方法总是会遵守遇到的顺序。 - tsolakpIterator
不会改变Spliterator
的顺序,因此你只是把问题转化为“并行流上的spliterator()
是否保证遇到顺序?” - Holgeriterator()
生成按不同顺序迭代的Iterator
与生成按不同顺序包含元素的collect()
的List
一样,都会导致“结果的变化”。是的,它会。这是因为终端操作(除非在文档中另有说明,例如forEach
- 明确指定为非确定性而不是forEachOrdered
)会保留遇到的顺序。而你的Stream.of
确实返回一个有序的流;这个顺序没有被任何地方打破(例如通过unordered
或sorted/distinct
)。
filter
或 map
这样的简单操作甚至都没有关于保持顺序的说明。即使对于 reduce
和 collect
,您也只能从函数必须结合但不需要交换律这一事实中推导出维护顺序的规则。 - Holger考虑到文档中所述的Stream.of返回有序流,以及您展示的任何中间操作都不会改变这种行为,因此我们可以说,在枚举时,保证返回的iterator
按顺序提供值2, 3, 4
,因为在有序流或序列(例如List实现)上调用iterator
终端操作应该按照那个顺序产生元素。
因此,只要我们有一个有序源、中间操作和终端操作,它们遵守这个顺序,无论代码是按顺序还是并行执行,顺序都应该得到维护。
iterator()
遵循遇到顺序的依据是什么? - shmoselforEach()
不会,许多收集器也不会。 - shmoselforEach
... 但是如果一个流或源有指定的顺序(保留顺序),那么使用 Iterator
枚举元素时应该按照该顺序检索元素。 - Ousmane D.
IntStream.range(0,5).parallel().map(x -> x*2).toArray()
必须生成[0, 2, 4, 6, 8]
*。奇怪的是文档没有更清晰地说明哪些操作尊重遭遇顺序,特别是考虑到forEach()
、forEachOrdered()
的区别。 - shmosel