Reputation: 148
Stream.of(a, b, c).parallel().map(Object::toString).iterator();
Is the returned iterator guaranteed to provide the values a
, b
, c
in that order?
I'm aware toArray()
and collect()
guarantee collections with values in the correct order. Also, I'm not asking how to make a stream from an iterator.
Upvotes: 13
Views: 1746
Reputation: 132360
This is an oversight in the specification. If a stream has a defined encounter order, the intent was that its Iterator produce the elements in encounter order. If the stream has no defined encounter order, the Iterator will of course produce the elements in some order, but that order won't be defined.
I've filed bug JDK-8194952 to track the change to the specification.
It looks like others have crawled through enough of the implementation to show that it will indeed produce the elements in encounter order. In addition, our stream tests rely on this property. For example, the test for the toList
collector asserts that the elements in the list are present in the same order as they are obtained from the stream's Iterator. So it's probably safe for you to rely on this behavior, even though it isn't formally specified (yet).
Upvotes: 8
Reputation: 6573
The closest to a guarantee that I have found so far ist the following statement in the package documentaion for java.util.stream:
Except for operations identified as explicitly nondeterministic, such as findAny(), whether a stream executes sequentially or in parallel should not change the result of the computation.
Arguably, iterator()
producing an Iterator
iterating in a different order would be a "change in the result", just as much as producing a List
containing elements in a different order would be for collect()
.
Upvotes: 1
Reputation: 56423
Given the fact the Stream.of returns, an ordered stream as stated in the documentation and none of the intermediate operations you've shown change this behavior we can, therefore, say that the returned iterator
is guaranteed to provide the values 2, 3, 4
in order when enumerated because calling the iterator
terminal operation on an ordered stream or sequence (e.g. a List implementation) should produce elements in that order when enumerated over.
So it shouldn't matter whether the code is executed sequentially or in parallel as long as we have an ordered source, intermediate operation(s) & terminal operation which respects this order then the order should be maintained.
Upvotes: 0
Reputation: 178253
The Stream.of
method, used to create a stream from otherwise un-associated values, returns an sequential, ordered stream.
Returns a sequential ordered stream whose elements are the specified values.
According to the package Javadocs for java.util.stream
, Side Effects section:
IntStream.range(0,5).parallel().map(x -> x*2).toArray()
must produce[0, 2, 4, 6, 8]
This implies that parallel()
and map()
preserve whether the stream is sequential/ordered.
I've traced the implementation of the Stream
that Stream.of
creates to a class called ReferencePipeline
.
@Override
public final Iterator<P_OUT> iterator() {
return Spliterators.iterator(spliterator());
}
That implementation's iterator()
method defers to Spliterator.iterator()
, whose code adapts to the Iterator
interface by simply relying on the Spliterator
's tryAdvance
method, and does not change any stream characteristics:
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();
}
In conclusion, yes, the order is guaranteed because Stream.of
creates a "sequential ordered stream", and none of the operations you use above: parallel
, map
, or iterator
change the characteristics. In fact, iterator
uses the underlying Stream Spliterator
to iterate over the stream elements.
Upvotes: 3
Reputation: 120848
Yes it will. And that is because terminal operations, unless otherwise specified in the documentation (forEach
for example - that explicitly specifies this to be non-deterministic vs forEachOrdered
), they do preserve encounter order. And your Stream.of
does return an ordered stream; order that is not broken anywhere (via unordered
for example, or sorted/distinct
)
Upvotes: 0