Spec pass on Stream

Joe Bowbeer joe.bowbeer at gmail.com
Fri Jul 5 18:59:43 PDT 2013


Nice.

A few nits below.

1. I think "invoking" reads better in the paren. comment below:

"A stream should be operated on ([invoking] an intermediate or terminal
stream operation) only once."


2. I'm confused about stream vs. stream pipeline and execution mode vs.
orientation in the following sentences:

Streams are created with an initial choice of sequential or parallel
> execution.  The orientation of a stream pipeline may be modified by the
> {@link #sequential()} or {@link #parallel()} methods, and may be queried
> with the {@link #isParallel()} method.  Whether a stream pipeline executes
> in sequential or parallel is determined by the orientation of the stream
> instance on which the terminal operation is invoked.
>

First, I think it might be clearer to remove "orientation" and use
"execution mode" or "execution mode orientation" instead.

Second,what's the difference between a stream instance and a stream
pipeline?  The term "stream instance" is never defined, but I infer that it
may be one of the streams created by an intermediate transform op.  Stream
pipeline is defined previously, but some reiteration may be useful.

Here is my attempt at a fix-up, omitting the paren. sentence for brevity:

Streams are created with an initial execution mode of sequential or
> parallel.  The execution mode of a stream pipeline may be modified by the
> {@link #sequential()} or {@link #parallel()} methods, and may be queried
> with the {@link #isParallel()} method.  The ultimate execution mode of a
> stream pipeline is determined by the execution mode of the final stream
> instance on which the terminal operation is invoked.



3. As a general comment, that doesn't apply so much to the doc in this
message, I think there are too many parenthetical comments in the current
stream doc.  Remedies include (1) removing the parens in the case of a
complete sentence, (2) changing to comma-delimited phrases, and (3) moving
to a separate sentence.  Also try dashes for variety?  For example:

"A stream should be operated on — invoking an intermediate or
terminal stream operation — only once."

--Joe


On Fri, Jul 5, 2013 at 3:03 PM, Brian Goetz <brian.goetz at oracle.com> wrote:

> Here's my latest whack at the interface doc for Stream.  The intent is to
> cover the basic concepts (what is a stream) and the must-describes (no
> interference with source during pipeline execution) here, and then link to
> package doc for more detail.
>
> Ideally I would have liked to @inheritDoc this all from BaseStream to
> {,Int,Long,Double}Stream, but javadoc didn't cooperate, so there would
> likely be cutting and pasting across the five XxxStream interfaces.
>
> /**
>  * A sequence of elements supporting sequential and parallel aggregate
>  * operations. For example:
>  *
>  * <pre>{@code
>  *     int sum = widgets.stream()
>  *                      .filter(b -> b.getColor() == RED)
>  *                      .mapToInt(b -> b.getWeight())
>  *                      .sum();
>  * }</pre>
>  *
>  * In this example, {@code widgets} is a {@code Collection<Widget>}. We
> create
>  * a stream of {@code Widget} objects via {@link Collection#stream
> Collection.stream()},
>  * filter it to produce a stream containing only the red widgets, and then
>  * transform it into a stream of {@code int} values representing the
> weight of
>  * each red widget. Then this stream is summed to produce a total weight.
>  *
>  * <p>To perform a computation, stream
>  * <a href="package-summary.html#**StreamOps">operations</a> are composed
> into a
>  * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
>  * might be an array, a collection, a generator function, an IO channel,
>  * etc), zero or more <em>intermediate operations</em> (which transform a
>  * stream into another stream, such as {@link Stream#filter(Predicate)}),
> and a
>  * <em>terminal operation</em> (which produces a result or side-effect,
> such
>  * as {@link IntStream#sum()} or {@link IntStream#forEach(IntConsumer)**
> }).
>  * Streams are lazy; computation on the source data is only performed when
> the
>  * terminal operation is initiated, and source elements are consumed only
>  * as needed.
>  *
>  * <p>Collections and streams, while bearing some superficial similarities,
>  * have different goals.  Collections are primarily concerned with the
> efficient
>  * management of, and access to, their elements.  By contrast, streams do
> not
>  * provide a means to directly access or manipulate their elements, and are
>  * instead concerned with declaratively describing their source and the
>  * computational operations which will be performed in aggregate on that
> source.
>  * However, if the provided stream operations do not offer the desired
>  * functionality, the {@link #iterator()} and {@link #spliterator()}
> operations
>  * can be used to perform a controlled traversal.
>  *
>  * <p>A stream pipeline, like the "widgets" example above, can be viewed as
>  * a <em>query</em> on the stream source.  Unless the source was explicitly
>  * designed for concurrent modification (such as a {@link
> ConcurrentHashMap}),
>  * unpredictable or erroneous behavior may result from modifying the stream
>  * source while it is being queried.
>  *
>  * <p>Most stream operations accept parameters that describe user-specified
>  * behavior, such as the lambda expression {@code b -> b.getWeight()}
> passed to
>  * {@code mapToInt} in the example above.  Such parameters are always
> instances
>  * of a <a href="../function/package-**summary.html">functional
> interface</a> such
>  * as {@link java.util.function.Function}, and are often lambda
> expressions or
>  * method references.  These parameters can never be null, should not
> modify the
>  * stream source, and should be
>  * <a href="package-summary.html#**NonInterference">effectively
> stateless</a>
>  * (their result should not depend on any state that might change during
>  * execution of the stream pipeline.)
>  *
>  * <p>A stream should be operated on (invoke an intermediate or terminal
> stream
>  * operation) only once.  This rules out, for example, "forked" streams,
> where
>  * the same source feeds two or more pipelines, or multiple traversals of
> the
>  * same stream.  A stream implementation may throw {@link
> IllegalStateException}
>  * if it detects that the stream is being reused. However, since some
> stream
>  * operations may return their receiver rather than a new stream object,
> it may
>  * not be possible to detect reuse in all cases.
>  *
>  * <p>When executed (by initiating its terminal operation), stream
> pipelines may
>  * execute either sequentially or in
>  * <a href="package-summary.html#**Parallelism">parallel</a>.  This
>  * execution mode is a property of the stream.  Streams are created
>  * with an initial choice of sequential or parallel execution.  (For
> example,
>  * {@link Collection#stream() Collection.stream()} creates a sequential
> stream,
>  * and {@link Collection#parallelStream() Collection.parallelStream()}
> creates
>  * a parallel one.)  The orientation of a stream pipeline may be modified
> by
>  * the {@link #sequential()} or {@link #parallel()} methods, and may be
> queried
>  * with the {@link #isParallel()} method.  Whether a stream pipeline
> executes in
>  * sequential or parallel is determined by the orientation of the stream
>  * instance on which the terminal operation is invoked.
>  *
>  * @param <T> type of stream elements
>  * @since 1.8
>  * @see <a href="package-summary.html">**java.util.stream</a>
>  */
>


More information about the lambda-libs-spec-observers mailing list