diff -r ed59bead7654 -r 20e8b81964d5 jdk/src/share/classes/java/util/stream/package-info.java --- a/jdk/src/share/classes/java/util/stream/package-info.java Tue Oct 22 14:51:08 2013 -0700 +++ b/jdk/src/share/classes/java/util/stream/package-info.java Tue Oct 22 15:12:22 2013 -0700 @@ -219,31 +219,18 @@ * not modified at all during the execution of the stream pipeline. * The notable exception to this are streams whose sources are concurrent * collections, which are specifically designed to handle concurrent modification. + * Concurrent stream sources are those whose {@code Spliterator} reports the + * {@code CONCURRENT} characteristic. * - *

Accordingly, behavioral parameters passed to stream methods should never - * modify the stream's data source. An implementation is said to - * interfere with the data source if it modifies, or causes to be + *

Accordingly, behavioral parameters in stream pipelines whose source might + * not be concurrent should never modify the stream's data source. + * A behavioral parameter is said to interfere with a non-concurrent + * data source if it modifies, or causes to be * modified, the stream's data source. The need for non-interference applies * to all pipelines, not just parallel ones. Unless the stream source is * concurrent, modifying a stream's data source during execution of a stream * pipeline can cause exceptions, incorrect answers, or nonconformant behavior. * - *

Results may be nondeterministic or incorrect if the behavioral - * parameters of stream operations are stateful. A stateful lambda - * (or other object implementing the appropriate functional interface) is one - * whose result depends on any state which might change during the execution - * of the stream pipeline. An example of a stateful lambda is: - * - *

{@code
- *     Set seen = Collections.synchronizedSet(new HashSet<>());
- *     stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...
- * }
- * - * Here, if the mapping operation is performed in parallel, the results for the - * same input could vary from run to run, due to thread scheduling differences, - * whereas, with a stateless lambda expression the results would always be the - * same. - * * For well-behaved stream sources, the source can be modified before the * terminal operation commences and those modifications will be reflected in * the covered elements. For example, consider the following code: @@ -265,26 +252,54 @@ * Low-level stream * construction for requirements for building well-behaved streams. * - *

Some streams, particularly those whose stream sources are concurrent, can - * tolerate concurrent modification during execution of a stream pipeline. - * However, in no case -- even if the stream source is concurrent -- should - * behavioral parameters to stream operations modify the stream source. Modifying - * the stream source from within the stream source may cause pipeline execution - * to fail to terminate, produce inaccurate results, or throw exceptions. - * The following example shows inappropriate interference with the source: + *

Stateless behaviors

+ * + * Stream pipeline results may be nondeterministic or incorrect if the behavioral + * parameters to the stream operations are stateful. A stateful lambda + * (or other object implementing the appropriate functional interface) is one + * whose result depends on any state which might change during the execution + * of the stream pipeline. An example of a stateful lambda is the parameter + * to {@code map()} in: + * *
{@code
- *     // Don't do this!
- *     List l = new ArrayList(Arrays.asList("one", "two"));
- *     Stream sl = l.stream();
- *     String s = sl.peek(s -> l.add("BAD LAMBDA")).collect(joining(" "));
+ *     Set seen = Collections.synchronizedSet(new HashSet<>());
+ *     stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...
  * }
* + * Here, if the mapping operation is performed in parallel, the results for the + * same input could vary from run to run, due to thread scheduling differences, + * whereas, with a stateless lambda expression the results would always be the + * same. + * + *

Note also that attempting to access mutable state from behavioral parameters + * presents you with a bad choice with respect to safety and performance; if + * you do not synchronize access to that state, you have a data race and + * therefore your code is broken, but if you do synchronize access to that + * state, you risk having contention undermine the parallelism you are seeking + * to benefit from. The best approach is to avoid stateful behavioral + * parameters to stream operations entirely; there is usually a way to + * restructure the stream pipeline to avoid statefulness. + * *

Side-effects

* * Side-effects in behavioral parameters to stream operations are, in general, * discouraged, as they can often lead to unwitting violations of the - * statelessness requirement, as well as other thread-safety hazards. Many - * computations where one might be tempted to use side effects can be more + * statelessness requirement, as well as other thread-safety hazards. + * + *

If the behavioral parameters do have side-effects, unless explicitly + * stated, there are no guarantees as to the + * visibility + * of those side-effects to other threads, nor are there any guarantees that + * different operations on the "same" element within the same stream pipeline + * are executed in the same thread. Further, the ordering of those effects + * may be surprising. Even when a pipeline is constrained to produce a + * result that is consistent with the encounter order of the stream + * source (for example, {@code IntStream.range(0,5).parallel().map(x -> x*2).toArray()} + * must produce {@code [0, 2, 4, 6, 8]}), no guarantees are made as to the order + * in which the mapper function is applied to individual elements, or in what + * thread any behavioral parameter is executed for a given element. + * + *

Many computations where one might be tempted to use side effects can be more * safely and efficiently expressed without side-effects, such as using * reduction instead of mutable * accumulators. However, side-effects such as using {@code println()} for debugging