From 53ef4fecbfcc3a38c9ded5211e7e3bbcfe5ba760 Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Fri, 20 May 2016 11:47:39 +0200 Subject: [PATCH] 8130023: API java.util.stream: explicitly specify guaranteed execution of the pipeline Reviewed-by: briangoetz, redestad --- .../java/util/stream/DoubleStream.java | 5 +++ .../classes/java/util/stream/IntStream.java | 5 +++ .../classes/java/util/stream/LongStream.java | 5 +++ .../classes/java/util/stream/Stream.java | 18 ++++++++++ .../java/util/stream/package-info.java | 33 ++++++++++++++----- 5 files changed, 58 insertions(+), 8 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/stream/DoubleStream.java b/jdk/src/java.base/share/classes/java/util/stream/DoubleStream.java index 9d25d902bb4..d25aabfbc4d 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/DoubleStream.java +++ b/jdk/src/java.base/share/classes/java/util/stream/DoubleStream.java @@ -211,6 +211,11 @@ public interface DoubleStream extends BaseStream { * .sum(); * } * + *

In cases where stream implementation is able to optimize away the + * production of some or all the elements (such as with short-circuiting + * operations like {@code findFirst}, or in the example described in + * {@link #count}), the action will not be invoked for those elements. + * * @param action a * non-interfering action to perform on the elements as * they are consumed from the stream diff --git a/jdk/src/java.base/share/classes/java/util/stream/IntStream.java b/jdk/src/java.base/share/classes/java/util/stream/IntStream.java index 115a782937f..2586de45240 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/IntStream.java +++ b/jdk/src/java.base/share/classes/java/util/stream/IntStream.java @@ -209,6 +209,11 @@ public interface IntStream extends BaseStream { * .sum(); * } * + *

In cases where stream implementation is able to optimize away the + * production of some or all the elements (such as with short-circuiting + * operations like {@code findFirst}, or in the example described in + * {@link #count}), the action will not be invoked for those elements. + * * @param action a * non-interfering action to perform on the elements as * they are consumed from the stream diff --git a/jdk/src/java.base/share/classes/java/util/stream/LongStream.java b/jdk/src/java.base/share/classes/java/util/stream/LongStream.java index f987820c5a8..d01b79ae507 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/LongStream.java +++ b/jdk/src/java.base/share/classes/java/util/stream/LongStream.java @@ -209,6 +209,11 @@ public interface LongStream extends BaseStream { * .sum(); * } * + *

In cases where stream implementation is able to optimize away the + * production of some or all the elements (such as with short-circuiting + * operations like {@code findFirst}, or in the example described in + * {@link #count}), the action will not be invoked for those elements. + * * @param action a * non-interfering action to perform on the elements as * they are consumed from the stream diff --git a/jdk/src/java.base/share/classes/java/util/stream/Stream.java b/jdk/src/java.base/share/classes/java/util/stream/Stream.java index 1dd1d43f91d..ac610dd6199 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/Stream.java +++ b/jdk/src/java.base/share/classes/java/util/stream/Stream.java @@ -82,6 +82,19 @@ import java.util.function.UnaryOperator; * terminal operation is initiated, and source elements are consumed only * as needed. * + *

A stream implementation is permitted significant latitude in optimizing + * the computation of the result. For example, a stream implementation is free + * to elide operations (or entire stages) from a stream pipeline -- and + * therefore elide invocation of behavioral parameters -- if it can prove that + * it would not affect the result of the computation. This means that + * side-effects of behavioral parameters may not always be executed and should + * not be relied upon, unless otherwise specified (such as by the terminal + * operations {@code forEach} and {@code forEachOrdered}). (For a specific + * example of such an optimization, see the API note documented on the + * {@link #count} operation. For more detail, see the + * side-effects section of the + * strean package documentation.) + * *

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 @@ -415,6 +428,11 @@ public interface Stream extends BaseStream> { * .collect(Collectors.toList()); * } * + *

In cases where stream implementation is able to optimize away the + * production of some or all the elements (such as with short-circuiting + * operations like {@code findFirst}, or in the example described in + * {@link #count}), the action will not be invoked for those elements. + * * @param action a * non-interfering action to perform on the elements as * they are consumed from the stream diff --git a/jdk/src/java.base/share/classes/java/util/stream/package-info.java b/jdk/src/java.base/share/classes/java/util/stream/package-info.java index 2850e21bbbd..f580d8fb372 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/package-info.java +++ b/jdk/src/java.base/share/classes/java/util/stream/package-info.java @@ -287,18 +287,35 @@ * 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()} + * stated, there are no guarantees as to: + *

+ *

The ordering of side-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. * + *

The eliding of side-effects may also be surprising. With the exception of + * terminal operations {@link java.util.stream.Stream#forEach forEach} and + * {@link java.util.stream.Stream#forEachOrdered forEachOrdered}, side-effects + * of behavioral parameters may not always be executed when the stream + * implementation can optimize away the execution of behavioral parameters + * without affecting the result of the computation. (For a specific example + * see the API note documented on the {@link java.util.stream.Stream#count count} + * operation.) + * *

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