提交 f884bcee 编写于 作者: H henryjen

8025909: Lambda Library Spec Updates

8024179: Document limitations and performance characteristics of stream sources and operations
8024138: (Spec clarification) Lambda Metafacory spec should state DMH constraint on implMethod
Reviewed-by: mduigou
Contributed-by: brian.goetz@oracle.com, paul.sandoz@oracle.com
上级 0cfffffa
......@@ -51,10 +51,12 @@ public interface Iterable<T> {
Iterator<T> iterator();
/**
* Performs the given action on the contents of the {@code Iterable}, in the
* order elements occur when iterating, until all elements have been
* processed or the action throws an exception. Errors or runtime
* exceptions thrown by the action are relayed to the caller.
* Performs the given action for each element of the {@code Iterable}
* until all elements have been processed or the action throws an
* exception. Unless otherwise specified by the implementing class,
* actions are performed in the order of iteration (if an iteration order
* is specified). Exceptions thrown by the action are relayed to the
* caller.
*
* @implSpec
* <p>The default implementation behaves as if:
......
......@@ -183,15 +183,15 @@ public class LambdaMetafactory {
* @param samMethodType MethodType of the method in the functional interface
* to which the lambda or method reference is being
* converted, represented as a MethodType.
* @param implMethod The implementation method which should be called
* (with suitable adaptation of argument types, return
* types, and adjustment for captured arguments) when
* methods of the resulting functional interface instance
* are invoked.
* @param implMethod A direct method handle describing the implementation
* method which should be called (with suitable adaptation
* of argument types, return types, and adjustment for
* captured arguments) when methods of the resulting
* functional interface instance are invoked.
* @param instantiatedMethodType The signature of the primary functional
* interface method after type variables
* are substituted with their instantiation
* from the capture site
* from the capture site.
* @return a CallSite, which, when invoked, will return an instance of the
* functional interface
* @throws ReflectiveOperationException if the caller is not able to
......@@ -220,15 +220,21 @@ public class LambdaMetafactory {
* references to functional interfaces, which supports serialization and
* other uncommon options.
*
* The declared argument list for this method is:
* <p>The declared argument list for this method is:
*
* <pre>{@code
* CallSite altMetafactory(MethodHandles.Lookup caller,
* String invokedName,
* MethodType invokedType,
* Object... args)
* }</pre>
*
* but it behaves as if the argument list is:
* <p>but it behaves as if the argument list is as follows, where names that
* appear in the argument list for
* {@link #metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)}
* have the same specification as in that method:
*
* <pre>{@code
* CallSite altMetafactory(MethodHandles.Lookup caller,
* String invokedName,
* MethodType invokedType,
......@@ -241,7 +247,15 @@ public class LambdaMetafactory {
* int bridgeCount, // IF flags has BRIDGES set
* MethodType... bridges // IF flags has BRIDGES set
* )
* }</pre>
*
* <p>If the flags contains {@code FLAG_SERIALIZABLE}, or one of the marker
* interfaces extends {@link Serializable}, the metafactory will link the
* call site to one that produces a serializable lambda. In addition to
* the lambda instance implementing {@code Serializable}, it will have a
* {@code writeReplace} method that returns an appropriate {@link
* SerializedLambda}, and an appropriate {@code $deserializeLambda$}
* method.
*
* @param caller Stacked automatically by VM; represents a lookup context
* with the accessibility privileges of the caller.
......@@ -257,7 +271,7 @@ public class LambdaMetafactory {
* In the event that the implementation method is an
* instance method, the first argument in the invocation
* signature will correspond to the receiver.
* @param args flags and optional arguments, as described above
* @param args flags and optional arguments, as described above.
* @return a CallSite, which, when invoked, will return an instance of the
* functional interface
* @throws ReflectiveOperationException if the caller is not able to
......
......@@ -32,9 +32,26 @@ import java.security.PrivilegedExceptionAction;
import java.util.Objects;
/**
* Serialized form of a lambda expression. The properties of this class represent the information that is present
* at the lambda factory site, including the identity of the primary functional interface method, the identity of the
* implementation method, and any variables captured from the local environment at the time of lambda capture.
* Serialized form of a lambda expression. The properties of this class
* represent the information that is present at the lambda factory site, including
* static metafactory arguments such as the identity of the primary functional
* interface method and the identity of the implementation method, as well as
* dynamic metafactory arguments such as values captured from the lexical scope
* at the time of lambda capture.
*
* <p>Implementors of serializable lambdas, such as compilers or language
* runtime libraries, are expected to ensure that instances deserialize properly.
* One means to do so is to ensure that the {@code writeReplace} method returns
* an instance of {@code SerializedLambda}, rather than allowing default
* serialization to proceed.
*
* <p>{@code SerializedLambda} has a {@code readResolve} method that looks for
* a (possibly private) static method called
* {@code $deserializeLambda$(SerializedLambda)} in the capturing class, invokes
* that with itself as the first argument, and returns the result. Lambda classes
* implementing {@code $deserializeLambda$} are responsible for validating
* that the properties of the {@code SerializedLambda} are consistent with a
* lambda actually captured by that class.
*
* @see LambdaMetafactory
*/
......
......@@ -127,7 +127,7 @@ public class DoubleSummaryStatistics implements DoubleConsumer {
* numerical sum compared to a simple summation of {@code double}
* values.
*
* @apiNote Sorting values by increasing absolute magnitude tends to yield
* @apiNote Values sorted by increasing absolute magnitude tend to yield
* more accurate results.
*
* @return the sum of values, or zero if none
......
......@@ -94,10 +94,10 @@ public interface Iterator<E> {
}
/**
* Performs the given action for each remaining element, in the order
* elements occur when iterating, until all elements have been processed or
* the action throws an exception. Errors or runtime exceptions thrown by
* the action are relayed to the caller.
* Performs the given action for each remaining element until all elements
* have been processed or the action throws an exception. Actions are
* performed in the order of iteration, if that order is specified.
* Exceptions thrown by the action are relayed to the caller.
*
* @implSpec
* <p>The default implementation behaves as if:
......
......@@ -192,8 +192,9 @@ public interface List<E> extends Collection<E> {
* The following code can be used to dump the list into a newly
* allocated array of <tt>String</tt>:
*
* <pre>
* String[] y = x.toArray(new String[0]);</pre>
* <pre>{@code
* String[] y = x.toArray(new String[0]);
* }</pre>
*
* Note that <tt>toArray(new Object[0])</tt> is identical in function to
* <tt>toArray()</tt>.
......@@ -383,14 +384,13 @@ public interface List<E> extends Collection<E> {
*
* @implSpec
* The default implementation is equivalent to, for this {@code list}:
* <pre>
* {@code
* final ListIterator<E> li = list.listIterator();
* while (li.hasNext()) {
* li.set(operator.apply(li.next()));
* }
* }
* </pre>
* <pre>{@code
* final ListIterator<E> li = list.listIterator();
* while (li.hasNext()) {
* li.set(operator.apply(li.next()));
* }
* }</pre>
*
* If the list's list-iterator does not support the {@code set} operation
* then an {@code UnsupportedOperationException} will be thrown when
* replacing the first element.
......@@ -469,11 +469,11 @@ public interface List<E> extends Collection<E> {
/**
* Returns the hash code value for this list. The hash code of a list
* is defined to be the result of the following calculation:
* <pre>
* int hashCode = 1;
* for (E e : list)
* hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
* </pre>
* <pre>{@code
* int hashCode = 1;
* for (E e : list)
* hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
* }</pre>
* This ensures that <tt>list1.equals(list2)</tt> implies that
* <tt>list1.hashCode()==list2.hashCode()</tt> for any two lists,
* <tt>list1</tt> and <tt>list2</tt>, as required by the general
......@@ -640,9 +640,9 @@ public interface List<E> extends Collection<E> {
* a list can be used as a range operation by passing a subList view
* instead of a whole list. For example, the following idiom
* removes a range of elements from a list:
* <pre>
* <pre>{@code
* list.subList(from, to).clear();
* </pre>
* }</pre>
* Similar idioms may be constructed for <tt>indexOf</tt> and
* <tt>lastIndexOf</tt>, and all of the algorithms in the
* <tt>Collections</tt> class can be applied to a subList.<p>
......
......@@ -562,9 +562,8 @@ public interface Map<K,V> {
// Defaultable methods
/**
* Returns the value to which the specified key is mapped,
* or {@code defaultValue} if this map contains no mapping
* for the key.
* Returns the value to which the specified key is mapped, or
* {@code defaultValue} if this map contains no mapping for the key.
*
* <p>The default implementation makes no guarantees about synchronization
* or atomicity properties of this method. Any implementation providing
......@@ -591,9 +590,10 @@ public interface Map<K,V> {
}
/**
* Performs the given action on each entry in this map, in the order entries
* are returned by an entry set iterator (which may be unspecified), until
* all entries have been processed or the action throws an {@code Exception}.
* Performs the given action for each entry in this map until all entries
* have been processed or the action throws an exception. Unless
* otherwise specified by the implementing class, actions are performed in
* the order of entry set iteration (if an iteration order is specified.)
* Exceptions thrown by the action are relayed to the caller.
*
* <p>The default implementation should be overridden by implementations if
......@@ -636,9 +636,9 @@ public interface Map<K,V> {
/**
* Replaces each entry's value with the result of invoking the given
* function on that entry, in the order entries are returned by an entry
* set iterator, until all entries have been processed or the function
* throws an exception.
* function on that entry until all entries have been processed or the
* function throws an exception. Exceptions thrown by the function are
* relayed to the caller.
*
* <p>The default implementation makes no guarantees about synchronization
* or atomicity properties of this method. Any implementation providing
......
......@@ -76,6 +76,7 @@ public interface PrimitiveIterator<T, T_CONS> extends Iterator<T> {
* @param action The action to be performed for each element
* @throws NullPointerException if the specified action is null
*/
@SuppressWarnings("overloads")
void forEachRemaining(T_CONS action);
/**
......@@ -93,10 +94,10 @@ public interface PrimitiveIterator<T, T_CONS> extends Iterator<T> {
int nextInt();
/**
* Performs the given action for each remaining element, in the order
* elements occur when iterating, until all elements have been processed
* or the action throws an exception. Errors or runtime exceptions
* thrown by the action are relayed to the caller.
* Performs the given action for each remaining element until all elements
* have been processed or the action throws an exception. Actions are
* performed in the order of iteration, if that order is specified.
* Exceptions thrown by the action are relayed to the caller.
*
* @implSpec
* <p>The default implementation behaves as if:
......@@ -167,10 +168,10 @@ public interface PrimitiveIterator<T, T_CONS> extends Iterator<T> {
long nextLong();
/**
* Performs the given action for each remaining element, in the order
* elements occur when iterating, until all elements have been processed
* or the action throws an exception. Errors or runtime exceptions
* thrown by the action are relayed to the caller.
* Performs the given action for each remaining element until all elements
* have been processed or the action throws an exception. Actions are
* performed in the order of iteration, if that order is specified.
* Exceptions thrown by the action are relayed to the caller.
*
* @implSpec
* <p>The default implementation behaves as if:
......@@ -240,10 +241,10 @@ public interface PrimitiveIterator<T, T_CONS> extends Iterator<T> {
double nextDouble();
/**
* Performs the given action for each remaining element, in the order
* elements occur when iterating, until all elements have been processed
* or the action throws an exception. Errors or runtime exceptions
* thrown by the action are relayed to the caller.
* Performs the given action for each remaining element until all elements
* have been processed or the action throws an exception. Actions are
* performed in the order of iteration, if that order is specified.
* Exceptions thrown by the action are relayed to the caller.
*
* @implSpec
* <p>The default implementation behaves as if:
......
......@@ -613,6 +613,7 @@ public interface Spliterator<T> {
* upon entry to this method, else {@code true}.
* @throws NullPointerException if the specified action is null
*/
@SuppressWarnings("overloads")
boolean tryAdvance(T_CONS action);
/**
......@@ -630,6 +631,7 @@ public interface Spliterator<T> {
* @param action The action
* @throws NullPointerException if the specified action is null
*/
@SuppressWarnings("overloads")
default void forEachRemaining(T_CONS action) {
do { } while (tryAdvance(action));
}
......
......@@ -60,7 +60,11 @@
* actions, or predicates. In documenting functional interfaces, or referring
* to variables typed as functional interfaces, it is common to refer directly
* to those abstract concepts, for example using "this function" instead of
* "the function represented by this object".
* "the function represented by this object". When an API method is said to
* accept or return a functional interface in this manner, such as "applies the
* provided function to...", this is understood to mean a <i>non-null</i>
* reference to an object implementing the appropriate functional interface,
* unless potential nullity is explicitly specified.
*
* <p>The functional interfaces in this package follow an extensible naming
* convention, as follows:
......
......@@ -35,9 +35,10 @@ import java.util.function.IntConsumer;
import java.util.function.Predicate;
/**
* A sequence of elements supporting sequential and parallel aggregate
* operations. The following example illustrates an aggregate operation using
* {@link Stream} and {@link IntStream}:
* Base interface for streams, which are sequences of elements supporting
* sequential and parallel aggregate operations. The following example
* illustrates an aggregate operation using the stream types {@link Stream}
* and {@link IntStream}, computing the sum of the weights of the red widgets:
*
* <pre>{@code
* int sum = widgets.stream()
......@@ -46,80 +47,18 @@ import java.util.function.Predicate;
* .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 w -> w.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 (invoking 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>Streams have a {@link #close()} method and implement {@link AutoCloseable},
* but nearly all stream instances do not actually need to be closed after use.
* Generally, only streams whose source is an IO channel (such as those returned
* by {@link Files#lines(Path, Charset)}) will require closing. Most streams
* are backed by collections, arrays, or generating functions, which require no
* special resource management. (If a stream does require closing, it can be
* declared as a resource in a {@code try}-with-resources statement.)
*
* <p>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.) This choice of execution mode may be modified by the
* {@link #sequential()} or {@link #parallel()} methods, and may be queried with
* the {@link #isParallel()} method.
* See the class documentation for {@link Stream} and the package documentation
* for <a href="package-summary.html">java.util.stream</a> for additional
* specification of streams, stream operations, stream pipelines, and
* parallelism, which governs the behavior of all stream types.
*
* @param <T> the type of the stream elements
* @param <S> the type of of the stream implementing {@code BaseStream}
* @since 1.8
* @see Stream
* @see IntStream
* @see LongStream
* @see DoubleStream
* @see <a href="package-summary.html">java.util.stream</a>
*/
public interface BaseStream<T, S extends BaseStream<T, S>>
......
......@@ -462,7 +462,7 @@ public final class Collectors {
*/
public static <T> Collector<T, ?, Integer>
summingInt(ToIntFunction<? super T> mapper) {
return new CollectorImpl<T, int[], Integer>(
return new CollectorImpl<>(
() -> new int[1],
(a, t) -> { a[0] += mapper.applyAsInt(t); },
(a, b) -> { a[0] += b[0]; return a; },
......@@ -480,7 +480,7 @@ public final class Collectors {
*/
public static <T> Collector<T, ?, Long>
summingLong(ToLongFunction<? super T> mapper) {
return new CollectorImpl<T, long[], Long>(
return new CollectorImpl<>(
() -> new long[1],
(a, t) -> { a[0] += mapper.applyAsLong(t); },
(a, b) -> { a[0] += b[0]; return a; },
......@@ -505,7 +505,7 @@ public final class Collectors {
*/
public static <T> Collector<T, ?, Double>
summingDouble(ToDoubleFunction<? super T> mapper) {
return new CollectorImpl<T, double[], Double>(
return new CollectorImpl<>(
() -> new double[1],
(a, t) -> { a[0] += mapper.applyAsDouble(t); },
(a, b) -> { a[0] += b[0]; return a; },
......@@ -523,7 +523,7 @@ public final class Collectors {
*/
public static <T> Collector<T, ?, Double>
averagingInt(ToIntFunction<? super T> mapper) {
return new CollectorImpl<T, long[], Double>(
return new CollectorImpl<>(
() -> new long[2],
(a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; },
(a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
......@@ -541,7 +541,7 @@ public final class Collectors {
*/
public static <T> Collector<T, ?, Double>
averagingLong(ToLongFunction<? super T> mapper) {
return new CollectorImpl<T, long[], Double>(
return new CollectorImpl<>(
() -> new long[2],
(a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; },
(a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
......@@ -566,7 +566,7 @@ public final class Collectors {
*/
public static <T> Collector<T, ?, Double>
averagingDouble(ToDoubleFunction<? super T> mapper) {
return new CollectorImpl<T, double[], Double>(
return new CollectorImpl<>(
() -> new double[2],
(a, t) -> { a[0] += mapper.applyAsDouble(t); a[1]++; },
(a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
......@@ -723,6 +723,14 @@ public final class Collectors {
* groupingBy(classifier, toList());
* }</pre>
*
* @implNote
* The returned {@code Collector} is not concurrent. For parallel stream
* pipelines, the {@code combiner} function operates by merging the keys
* from one map into another, which can be an expensive operation. If
* preservation of the order in which elements appear in the resulting {@code Map}
* collector is not required, using {@link #groupingByConcurrent(Function)}
* may offer better parallel performance.
*
* @param <T> the type of the input elements
* @param <K> the type of the keys
* @param classifier the classifier function mapping input elements to keys
......@@ -759,6 +767,14 @@ public final class Collectors {
* mapping(Person::getLastName, toSet())));
* }</pre>
*
* @implNote
* The returned {@code Collector} is not concurrent. For parallel stream
* pipelines, the {@code combiner} function operates by merging the keys
* from one map into another, which can be an expensive operation. If
* preservation of the order in which elements are presented to the downstream
* collector is not required, using {@link #groupingByConcurrent(Function, Collector)}
* may offer better parallel performance.
*
* @param <T> the type of the input elements
* @param <K> the type of the keys
* @param <A> the intermediate accumulation type of the downstream collector
......@@ -798,6 +814,14 @@ public final class Collectors {
* mapping(Person::getLastName, toSet())));
* }</pre>
*
* @implNote
* The returned {@code Collector} is not concurrent. For parallel stream
* pipelines, the {@code combiner} function operates by merging the keys
* from one map into another, which can be an expensive operation. If
* preservation of the order in which elements are presented to the downstream
* collector is not required, using {@link #groupingByConcurrent(Function, Supplier, Collector)}
* may offer better parallel performance.
*
* @param <T> the type of the input elements
* @param <K> the type of the keys
* @param <A> the intermediate accumulation type of the downstream collector
......@@ -871,7 +895,7 @@ public final class Collectors {
* @param <T> the type of the input elements
* @param <K> the type of the keys
* @param classifier a classifier function mapping input elements to keys
* @return a {@code Collector} implementing the group-by operation
* @return a concurrent, unordered {@code Collector} implementing the group-by operation
*
* @see #groupingBy(Function)
* @see #groupingByConcurrent(Function, Collector)
......@@ -912,7 +936,7 @@ public final class Collectors {
* @param <D> the result type of the downstream reduction
* @param classifier a classifier function mapping input elements to keys
* @param downstream a {@code Collector} implementing the downstream reduction
* @return a {@code Collector} implementing the cascaded group-by operation
* @return a concurrent, unordered {@code Collector} implementing the cascaded group-by operation
*
* @see #groupingBy(Function, Collector)
* @see #groupingByConcurrent(Function)
......@@ -958,7 +982,7 @@ public final class Collectors {
* @param downstream a {@code Collector} implementing the downstream reduction
* @param mapFactory a function which, when called, produces a new empty
* {@code ConcurrentMap} of the desired type
* @return a {@code Collector} implementing the cascaded group-by operation
* @return a concurrent, unordered {@code Collector} implementing the cascaded group-by operation
*
* @see #groupingByConcurrent(Function)
* @see #groupingByConcurrent(Function, Collector)
......@@ -1072,7 +1096,7 @@ public final class Collectors {
}
/**
* Returns a {@code Collector} that accumulate elements into a
* Returns a {@code Collector} that accumulates elements into a
* {@code Map} whose keys and values are the result of applying the provided
* mapping functions to the input elements.
*
......@@ -1101,6 +1125,14 @@ public final class Collectors {
* Functions.identity());
* }</pre>
*
* @implNote
* The returned {@code Collector} is not concurrent. For parallel stream
* pipelines, the {@code combiner} function operates by merging the keys
* from one map into another, which can be an expensive operation. If it is
* not required that results are inserted into the {@code Map} in encounter
* order, using {@link #toConcurrentMap(Function, Function)}
* may offer better parallel performance.
*
* @param <T> the type of the input elements
* @param <K> the output type of the key mapping function
* @param <U> the output type of the value mapping function
......@@ -1121,7 +1153,7 @@ public final class Collectors {
}
/**
* Returns a {@code Collector} that accumulate elements into a
* Returns a {@code Collector} that accumulates elements into a
* {@code Map} whose keys and values are the result of applying the provided
* mapping functions to the input elements.
*
......@@ -1146,6 +1178,14 @@ public final class Collectors {
* (s, a) -> s + ", " + a));
* }</pre>
*
* @implNote
* The returned {@code Collector} is not concurrent. For parallel stream
* pipelines, the {@code combiner} function operates by merging the keys
* from one map into another, which can be an expensive operation. If it is
* not required that results are merged into the {@code Map} in encounter
* order, using {@link #toConcurrentMap(Function, Function, BinaryOperator)}
* may offer better parallel performance.
*
* @param <T> the type of the input elements
* @param <K> the output type of the key mapping function
* @param <U> the output type of the value mapping function
......@@ -1172,7 +1212,7 @@ public final class Collectors {
}
/**
* Returns a {@code Collector} that accumulate elements into a
* Returns a {@code Collector} that accumulates elements into a
* {@code Map} whose keys and values are the result of applying the provided
* mapping functions to the input elements.
*
......@@ -1182,6 +1222,14 @@ public final class Collectors {
* results are merged using the provided merging function. The {@code Map}
* is created by a provided supplier function.
*
* @implNote
* The returned {@code Collector} is not concurrent. For parallel stream
* pipelines, the {@code combiner} function operates by merging the keys
* from one map into another, which can be an expensive operation. If it is
* not required that results are merged into the {@code Map} in encounter
* order, using {@link #toConcurrentMap(Function, Function, BinaryOperator, Supplier)}
* may offer better parallel performance.
*
* @param <T> the type of the input elements
* @param <K> the output type of the key mapping function
* @param <U> the output type of the value mapping function
......@@ -1215,7 +1263,7 @@ public final class Collectors {
}
/**
* Returns a {@code Collector} that accumulate elements into a
* Returns a concurrent {@code Collector} that accumulates elements into a
* {@code ConcurrentMap} whose keys and values are the result of applying
* the provided mapping functions to the input elements.
*
......@@ -1252,7 +1300,7 @@ public final class Collectors {
* @param <U> the output type of the value mapping function
* @param keyMapper the mapping function to produce keys
* @param valueMapper the mapping function to produce values
* @return a concurrent {@code Collector} which collects elements into a
* @return a concurrent, unordered {@code Collector} which collects elements into a
* {@code ConcurrentMap} whose keys are the result of applying a key mapping
* function to the input elements, and whose values are the result of
* applying a value mapping function to the input elements
......@@ -1268,7 +1316,7 @@ public final class Collectors {
}
/**
* Returns a {@code Collector} that accumulate elements into a
* Returns a concurrent {@code Collector} that accumulates elements into a
* {@code ConcurrentMap} whose keys and values are the result of applying
* the provided mapping functions to the input elements.
*
......@@ -1303,7 +1351,7 @@ public final class Collectors {
* @param mergeFunction a merge function, used to resolve collisions between
* values associated with the same key, as supplied
* to {@link Map#merge(Object, Object, BiFunction)}
* @return a concurrent {@code Collector} which collects elements into a
* @return a concurrent, unordered {@code Collector} which collects elements into a
* {@code ConcurrentMap} whose keys are the result of applying a key mapping
* function to the input elements, and whose values are the result of
* applying a value mapping function to all input elements equal to the key
......@@ -1322,7 +1370,7 @@ public final class Collectors {
}
/**
* Returns a {@code Collector} that accumulate elements into a
* Returns a concurrent {@code Collector} that accumulates elements into a
* {@code ConcurrentMap} whose keys and values are the result of applying
* the provided mapping functions to the input elements.
*
......@@ -1345,7 +1393,7 @@ public final class Collectors {
* to {@link Map#merge(Object, Object, BiFunction)}
* @param mapSupplier a function which returns a new, empty {@code Map} into
* which the results will be inserted
* @return a concurrent {@code Collector} which collects elements into a
* @return a concurrent, unordered {@code Collector} which collects elements into a
* {@code ConcurrentMap} whose keys are the result of applying a key mapping
* function to the input elements, and whose values are the result of
* applying a value mapping function to all input elements equal to the key
......
......@@ -51,9 +51,13 @@ import java.util.function.ObjLongConsumer;
import java.util.function.Supplier;
/**
* A sequence of elements supporting sequential and parallel aggregate
* operations. The following example illustrates an aggregate operation using
* {@link Stream} and {@link LongStream}:
* A sequence of primitive long-valued elements supporting sequential and parallel
* aggregate operations. This is the {@code long} primitive specialization of
* {@link Stream}.
*
* <p>The following example illustrates an aggregate operation using
* {@link Stream} and {@link LongStream}, computing the sum of the weights of the
* red widgets:
*
* <pre>{@code
* long sum = widgets.stream()
......@@ -62,78 +66,13 @@ import java.util.function.Supplier;
* .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 long} 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 LongStream#filter(LongPredicate)}), and a
* <em>terminal operation</em> (which produces a result or side-effect, such
* as {@link LongStream#sum()} or {@link LongStream#forEach(LongConsumer)}).
* 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 w -> w.getWeight()} passed to
* {@code mapToLong} 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 (invoking 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>Streams have a {@link #close()} method and implement {@link AutoCloseable},
* but nearly all stream instances do not actually need to be closed after use.
* Generally, only streams whose source is an IO channel (such as those returned
* by {@link Files#lines(Path, Charset)}) will require closing. Most streams
* are backed by collections, arrays, or generating functions, which require no
* special resource management. (If a stream does require closing, it can be
* declared as a resource in a {@code try}-with-resources statement.)
*
* <p>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.) This choice of execution mode may be modified by the
* {@link #sequential()} or {@link #parallel()} methods, and may be queried with
* the {@link #isParallel()} method.
* See the class documentation for {@link Stream} and the package documentation
* for <a href="package-summary.html">java.util.stream</a> for additional
* specification of streams, stream operations, stream pipelines, and
* parallelism.
*
* @since 1.8
* @see Stream
* @see <a href="package-summary.html">java.util.stream</a>
*/
public interface LongStream extends BaseStream<Long, LongStream> {
......@@ -145,9 +84,10 @@ public interface LongStream extends BaseStream<Long, LongStream> {
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* @param predicate a <a href="package-summary.html#NonInterference">
* non-interfering, stateless</a> predicate to apply to
* each element to determine if it should be included
* @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* predicate to apply to each element to determine if it
* should be included
* @return the new stream
*/
LongStream filter(LongPredicate predicate);
......@@ -159,9 +99,9 @@ public interface LongStream extends BaseStream<Long, LongStream> {
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* @param mapper a <a href="package-summary.html#NonInterference">
* non-interfering, stateless</a> function to apply to each
* element
* @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* function to apply to each element
* @return the new stream
*/
LongStream map(LongUnaryOperator mapper);
......@@ -174,9 +114,9 @@ public interface LongStream extends BaseStream<Long, LongStream> {
* intermediate operation</a>.
*
* @param <U> the element type of the new stream
* @param mapper a <a href="package-summary.html#NonInterference">
* non-interfering, stateless</a> function to apply to each
* element
* @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* function to apply to each element
* @return the new stream
*/
<U> Stream<U> mapToObj(LongFunction<? extends U> mapper);
......@@ -188,9 +128,9 @@ public interface LongStream extends BaseStream<Long, LongStream> {
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* @param mapper a <a href="package-summary.html#NonInterference">
* non-interfering, stateless</a> function to apply to each
* element
* @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* function to apply to each element
* @return the new stream
*/
IntStream mapToInt(LongToIntFunction mapper);
......@@ -202,9 +142,9 @@ public interface LongStream extends BaseStream<Long, LongStream> {
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* @param mapper a <a href="package-summary.html#NonInterference">
* non-interfering, stateless</a> function to apply to each
* element
* @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* function to apply to each element
* @return the new stream
*/
DoubleStream mapToDouble(LongToDoubleFunction mapper);
......@@ -219,10 +159,10 @@ public interface LongStream extends BaseStream<Long, LongStream> {
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* @param mapper a <a href="package-summary.html#NonInterference">
* non-interfering, stateless</a> function to apply to
* each element which produces an {@code LongStream} of new
* values
* @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* function to apply to each element which produces a
* {@code LongStream} of new values
* @return the new stream
* @see Stream#flatMap(Function)
*/
......@@ -421,9 +361,10 @@ public interface LongStream extends BaseStream<Long, LongStream> {
* synchronization and with greatly reduced risk of data races.
*
* @param identity the identity value for the accumulating function
* @param op an <a href="package-summary.html#Associativity">associative</a>
* <a href="package-summary.html#NonInterference">non-interfering,
* stateless</a> function for combining two values
* @param op an <a href="package-summary.html#Associativity">associative</a>,
* <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* function for combining two values
* @return the result of the reduction
* @see #sum()
* @see #min()
......@@ -460,9 +401,10 @@ public interface LongStream extends BaseStream<Long, LongStream> {
* <p>This is a <a href="package-summary.html#StreamOps">terminal
* operation</a>.
*
* @param op an <a href="package-summary.html#Associativity">associative</a>
* <a href="package-summary.html#NonInterference">non-interfering,
* stateless</a> function for combining two values
* @param op an <a href="package-summary.html#Associativity">associative</a>,
* <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* function for combining two values
* @return the result of the reduction
* @see #reduce(long, LongBinaryOperator)
*/
......@@ -492,14 +434,15 @@ public interface LongStream extends BaseStream<Long, LongStream> {
* @param supplier a function that creates a new result container. For a
* parallel execution, this function may be called
* multiple times and must return a fresh value each time.
* @param accumulator an <a href="package-summary.html#Associativity">associative</a>
* <a href="package-summary.html#NonInterference">non-interfering,
* stateless</a> function for incorporating an additional
* element into a result
* @param combiner an <a href="package-summary.html#Associativity">associative</a>
* <a href="package-summary.html#NonInterference">non-interfering,
* stateless</a> function for combining two values, which
* must be compatible with the accumulator function
* @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
* <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* function for incorporating an additional element into a result
* @param combiner an <a href="package-summary.html#Associativity">associative</a>,
* <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* function for combining two values, which must be
* compatible with the accumulator function
* @return the result of the reduction
* @see Stream#collect(Supplier, BiConsumer, BiConsumer)
*/
......@@ -599,48 +542,67 @@ public interface LongStream extends BaseStream<Long, LongStream> {
/**
* Returns whether any elements of this stream match the provided
* predicate. May not evaluate the predicate on all elements if not
* necessary for determining the result.
* necessary for determining the result. If the stream is empty then
* {@code false} is returned and the predicate is not evaluated.
*
* <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
* terminal operation</a>.
*
* @param predicate a <a href="package-summary.html#NonInterference">non-interfering,
* stateless</a> predicate to apply to elements of this
* stream
* @apiNote
* This method evaluates the <em>existential quantification</em> of the
* predicate over the elements of the stream (for some x P(x)).
*
* @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* predicate to apply to elements of this stream
* @return {@code true} if any elements of the stream match the provided
* predicate otherwise {@code false}
* predicate, otherwise {@code false}
*/
boolean anyMatch(LongPredicate predicate);
/**
* Returns whether all elements of this stream match the provided predicate.
* May not evaluate the predicate on all elements if not necessary for
* determining the result.
* determining the result. If the stream is empty then {@code true} is
* returned and the predicate is not evaluated.
*
* <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
* terminal operation</a>.
*
* @param predicate a <a href="package-summary.html#NonInterference">non-interfering,
* stateless</a> predicate to apply to elements of this
* stream
* @return {@code true} if all elements of the stream match the provided
* predicate otherwise {@code false}
* @apiNote
* This method evaluates the <em>universal quantification</em> of the
* predicate over the elements of the stream (for all x P(x)). If the
* stream is empty, the quantification is said to be <em>vacuously
* satisfied</em> and is always {@code true} (regardless of P(x)).
*
* @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* predicate to apply to elements of this stream
* @return {@code true} if either all elements of the stream match the
* provided predicate or the stream is empty, otherwise {@code false}
*/
boolean allMatch(LongPredicate predicate);
/**
* Returns whether no elements of this stream match the provided predicate.
* Returns whether no elements of this stream match the provided predicate.
* May not evaluate the predicate on all elements if not necessary for
* determining the result.
* determining the result. If the stream is empty then {@code true} is
* returned and the predicate is not evaluated.
*
* <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
* terminal operation</a>.
*
* @param predicate a <a href="package-summary.html#NonInterference">non-interfering,
* stateless</a> predicate to apply to elements of this
* stream
* @return {@code true} if no elements of the stream match the provided
* predicate otherwise {@code false}
* @apiNote
* This method evaluates the <em>universal quantification</em> of the
* negated predicate over the elements of the stream (for all x ~P(x)). If
* the stream is empty, the quantification is said to be vacuously satisfied
* and is always {@code true}, regardless of P(x).
*
* @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* predicate to apply to elements of this stream
* @return {@code true} if either no elements of the stream match the
* provided predicate or the stream is empty, otherwise {@code false}
*/
boolean noneMatch(LongPredicate predicate);
......@@ -791,12 +753,12 @@ public interface LongStream extends BaseStream<Long, LongStream> {
}
/**
* Returns a sequential stream where each element is generated by
* the provided {@code LongSupplier}. This is suitable for generating
* constant streams, streams of random elements, etc.
* Returns an infinite sequential unordered stream where each element is
* generated by the provided {@code LongSupplier}. This is suitable for
* generating constant streams, streams of random elements, etc.
*
* @param s the {@code LongSupplier} for generated elements
* @return a new sequential {@code LongStream}
* @return a new infinite sequential unordered {@code LongStream}
*/
public static LongStream generate(LongSupplier s) {
Objects.requireNonNull(s);
......@@ -874,11 +836,16 @@ public interface LongStream extends BaseStream<Long, LongStream> {
/**
* Creates a lazily concatenated stream whose elements are all the
* elements of the first stream followed by all the elements of the
* second stream. The resulting stream is ordered if both
* second stream. The resulting stream is ordered if both
* of the input streams are ordered, and parallel if either of the input
* streams is parallel. When the resulting stream is closed, the close
* handlers for both input streams are invoked.
*
* @implNote
* Use caution when constructing streams from repeated concatenation.
* Accessing an element of a deeply concatenated stream can result in deep
* call chains, or even {@code StackOverflowException}.
*
* @param a the first stream
* @param b the second stream
* @return the concatenation of the two input streams
......
......@@ -241,6 +241,7 @@ interface Node<T> {
* @param action a consumer that is to be invoked with each
* element in this {@code Node.OfPrimitive}
*/
@SuppressWarnings("overloads")
void forEach(T_CONS action);
@Override
......
......@@ -579,6 +579,7 @@ class SpinedBuffer<E>
spineIndex = 0;
}
@SuppressWarnings("overloads")
public void forEach(T_CONS consumer) {
// completed chunks, if any
for (int j = 0; j < spineIndex; j++)
......
......@@ -96,7 +96,8 @@ public final class StreamSupport {
* @param supplier a {@code Supplier} of a {@code Spliterator}
* @param characteristics Spliterator characteristics of the supplied
* {@code Spliterator}. The characteristics must be equal to
* {@code supplier.get().characteristics()}.
* {@code supplier.get().characteristics()}, otherwise undefined
* behavior may occur when terminal operation commences.
* @param parallel if {@code true} then the returned stream is a parallel
* stream; if {@code false} the returned stream is a sequential
* stream.
......@@ -163,7 +164,8 @@ public final class StreamSupport {
* @param supplier a {@code Supplier} of a {@code Spliterator.OfInt}
* @param characteristics Spliterator characteristics of the supplied
* {@code Spliterator.OfInt}. The characteristics must be equal to
* {@code supplier.get().characteristics()}
* {@code supplier.get().characteristics()}, otherwise undefined
* behavior may occur when terminal operation commences.
* @param parallel if {@code true} then the returned stream is a parallel
* stream; if {@code false} the returned stream is a sequential
* stream.
......@@ -230,7 +232,8 @@ public final class StreamSupport {
* @param supplier a {@code Supplier} of a {@code Spliterator.OfLong}
* @param characteristics Spliterator characteristics of the supplied
* {@code Spliterator.OfLong}. The characteristics must be equal to
* {@code supplier.get().characteristics()}
* {@code supplier.get().characteristics()}, otherwise undefined
* behavior may occur when terminal operation commences.
* @param parallel if {@code true} then the returned stream is a parallel
* stream; if {@code false} the returned stream is a sequential
* stream.
......@@ -297,7 +300,8 @@ public final class StreamSupport {
* @param supplier A {@code Supplier} of a {@code Spliterator.OfDouble}
* @param characteristics Spliterator characteristics of the supplied
* {@code Spliterator.OfDouble}. The characteristics must be equal to
* {@code supplier.get().characteristics()}
* {@code supplier.get().characteristics()}, otherwise undefined
* behavior may occur when terminal operation commences.
* @param parallel if {@code true} then the returned stream is a parallel
* stream; if {@code false} the returned stream is a sequential
* stream.
......
......@@ -219,31 +219,18 @@
* <em>not modified at all</em> 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.
*
* <p>Accordingly, behavioral parameters passed to stream methods should never
* modify the stream's data source. An implementation is said to
* <em>interfere</em> with the data source if it modifies, or causes to be
* <p>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 <em>interfere</em> 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.
*
* <p>Results may be nondeterministic or incorrect if the behavioral
* parameters of stream operations are <em>stateful</em>. 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:
*
* <pre>{@code
* Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());
* stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...
* }</pre>
*
* 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 @@
* <a href="package-summary.html#StreamSources">Low-level stream
* construction</a> for requirements for building well-behaved streams.
*
* <p>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:
* <h3><a name="Statelessness">Stateless behaviors</a></h3>
*
* Stream pipeline results may be nondeterministic or incorrect if the behavioral
* parameters to the stream operations are <em>stateful</em>. 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:
*
* <pre>{@code
* // Don't do this!
* List<String> l = new ArrayList(Arrays.asList("one", "two"));
* Stream<String> sl = l.stream();
* String s = sl.peek(s -> l.add("BAD LAMBDA")).collect(joining(" "));
* Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());
* stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...
* }</pre>
*
* 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.
*
* <p>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.
*
* <h3>Side-effects</h3>
*
* 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.
*
* <p>If the behavioral parameters do have side-effects, unless explicitly
* stated, there are no guarantees as to the
* <a href="../concurrent/package-summary.html#MemoryVisibility"><i>visibility</i></a>
* 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
* <em>result</em> 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.
*
* <p>Many computations where one might be tempted to use side effects can be more
* safely and efficiently expressed without side-effects, such as using
* <a href="package-summary.html#Reduction">reduction</a> instead of mutable
* accumulators. However, side-effects such as using {@code println()} for debugging
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册