diff --git a/src/share/classes/java/lang/Iterable.java b/src/share/classes/java/lang/Iterable.java index b6b5f26ba45a91af6160365a8b260e6b92bb2cf7..eed39388a8f8148e016eaf0bf3b3530a7278e5ae 100644 --- a/src/share/classes/java/lang/Iterable.java +++ b/src/share/classes/java/lang/Iterable.java @@ -51,10 +51,12 @@ public interface Iterable { Iterator 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 *

The default implementation behaves as if: diff --git a/src/share/classes/java/lang/invoke/LambdaMetafactory.java b/src/share/classes/java/lang/invoke/LambdaMetafactory.java index 87c7923d9babc508a459f310312b32809e1eab35..a5d2afab40ebe5c481f4f5dffa4b84cb8271c12d 100644 --- a/src/share/classes/java/lang/invoke/LambdaMetafactory.java +++ b/src/share/classes/java/lang/invoke/LambdaMetafactory.java @@ -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: + *

The declared argument list for this method is: * + *

{@code
      *  CallSite altMetafactory(MethodHandles.Lookup caller,
      *                          String invokedName,
      *                          MethodType invokedType,
      *                          Object... args)
+     * }
* - * but it behaves as if the argument list is: + *

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: * + *

{@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
      *                          )
+     * }
* + *

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 diff --git a/src/share/classes/java/lang/invoke/SerializedLambda.java b/src/share/classes/java/lang/invoke/SerializedLambda.java index 9be96ff685bdee8b2fcef7e914e540680f8f3ab4..e641201272155cf73f5ceecc8a2d0482baa3d8cc 100644 --- a/src/share/classes/java/lang/invoke/SerializedLambda.java +++ b/src/share/classes/java/lang/invoke/SerializedLambda.java @@ -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. + * + *

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. + * + *

{@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 */ diff --git a/src/share/classes/java/util/DoubleSummaryStatistics.java b/src/share/classes/java/util/DoubleSummaryStatistics.java index 947f47c2744dd3a05bc86f92496d58688ea8e901..be9d4b5ae560cd76efbdb725256524ff197402b1 100644 --- a/src/share/classes/java/util/DoubleSummaryStatistics.java +++ b/src/share/classes/java/util/DoubleSummaryStatistics.java @@ -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 diff --git a/src/share/classes/java/util/Iterator.java b/src/share/classes/java/util/Iterator.java index 4420d04995fd0c7e9e9cd9f3c4adf08ffd477e15..7d2daf8f96feb5bba18c21d20bd25f417a218414 100644 --- a/src/share/classes/java/util/Iterator.java +++ b/src/share/classes/java/util/Iterator.java @@ -94,10 +94,10 @@ public interface Iterator { } /** - * 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 *

The default implementation behaves as if: diff --git a/src/share/classes/java/util/List.java b/src/share/classes/java/util/List.java index 42a1acf22c58aa11c4fa9a3e716c9bf097cb9fcb..5cbd044169ba9ac8ad30ca18a7e877584bff40e0 100644 --- a/src/share/classes/java/util/List.java +++ b/src/share/classes/java/util/List.java @@ -192,8 +192,9 @@ public interface List extends Collection { * The following code can be used to dump the list into a newly * allocated array of String: * - *

-     *     String[] y = x.toArray(new String[0]);
+ *
{@code
+     *     String[] y = x.toArray(new String[0]);
+     * }
* * Note that toArray(new Object[0]) is identical in function to * toArray(). @@ -383,14 +384,13 @@ public interface List extends Collection { * * @implSpec * The default implementation is equivalent to, for this {@code list}: - *
-     * {@code
-     * final ListIterator li = list.listIterator();
-     * while (li.hasNext()) {
-     *   li.set(operator.apply(li.next()));
-     * }
-     * }
-     * 
+ *
{@code
+     *     final ListIterator li = list.listIterator();
+     *     while (li.hasNext()) {
+     *         li.set(operator.apply(li.next()));
+     *     }
+     * }
+ * * 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 extends Collection { /** * Returns the hash code value for this list. The hash code of a list * is defined to be the result of the following calculation: - *
-     *  int hashCode = 1;
-     *  for (E e : list)
-     *      hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
-     * 
+ *
{@code
+     *     int hashCode = 1;
+     *     for (E e : list)
+     *         hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
+     * }
* This ensures that list1.equals(list2) implies that * list1.hashCode()==list2.hashCode() for any two lists, * list1 and list2, as required by the general @@ -640,9 +640,9 @@ public interface List extends Collection { * 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: - *
+     * 
{@code
      *      list.subList(from, to).clear();
-     * 
+ * }
* Similar idioms may be constructed for indexOf and * lastIndexOf, and all of the algorithms in the * Collections class can be applied to a subList.

diff --git a/src/share/classes/java/util/Map.java b/src/share/classes/java/util/Map.java index d67e58db2482a6b985f4fd82a11881260d8e7238..0adf9d45bc5f4806484763d353100aa3bb96f25e 100644 --- a/src/share/classes/java/util/Map.java +++ b/src/share/classes/java/util/Map.java @@ -562,9 +562,8 @@ public interface Map { // 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. * *

The default implementation makes no guarantees about synchronization * or atomicity properties of this method. Any implementation providing @@ -591,9 +590,10 @@ public interface Map { } /** - * 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. * *

The default implementation should be overridden by implementations if @@ -636,9 +636,9 @@ public interface Map { /** * 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. * *

The default implementation makes no guarantees about synchronization * or atomicity properties of this method. Any implementation providing diff --git a/src/share/classes/java/util/PrimitiveIterator.java b/src/share/classes/java/util/PrimitiveIterator.java index 6689614b3377b8dfd47574e96ca20ec7fedcedb3..2bc864aa3febaa1c31e2f6ddf8025ccac11fb1bd 100644 --- a/src/share/classes/java/util/PrimitiveIterator.java +++ b/src/share/classes/java/util/PrimitiveIterator.java @@ -76,6 +76,7 @@ public interface PrimitiveIterator extends Iterator { * @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 extends Iterator { 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 *

The default implementation behaves as if: @@ -167,10 +168,10 @@ public interface PrimitiveIterator extends Iterator { 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 *

The default implementation behaves as if: @@ -240,10 +241,10 @@ public interface PrimitiveIterator extends Iterator { 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 *

The default implementation behaves as if: diff --git a/src/share/classes/java/util/Spliterator.java b/src/share/classes/java/util/Spliterator.java index b78bad659353b03460b29d9f090590c83cbec798..18cb082cf38afe5dc26f7b34fc1c58156cc5871a 100644 --- a/src/share/classes/java/util/Spliterator.java +++ b/src/share/classes/java/util/Spliterator.java @@ -613,6 +613,7 @@ public interface Spliterator { * 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 { * @param action The action * @throws NullPointerException if the specified action is null */ + @SuppressWarnings("overloads") default void forEachRemaining(T_CONS action) { do { } while (tryAdvance(action)); } diff --git a/src/share/classes/java/util/function/package-info.java b/src/share/classes/java/util/function/package-info.java index f437f9494b77950162fedd4813a7103e57cb09bd..ccb329cd98210cf17b8797d251b9adb725c8e862 100644 --- a/src/share/classes/java/util/function/package-info.java +++ b/src/share/classes/java/util/function/package-info.java @@ -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 non-null + * reference to an object implementing the appropriate functional interface, + * unless potential nullity is explicitly specified. * *

The functional interfaces in this package follow an extensible naming * convention, as follows: diff --git a/src/share/classes/java/util/stream/BaseStream.java b/src/share/classes/java/util/stream/BaseStream.java index 4b7006b59c04d766dd3c7fc0004b733096da1fd5..35d46e087279803994e42629250f5b21b2a80b4e 100644 --- a/src/share/classes/java/util/stream/BaseStream.java +++ b/src/share/classes/java/util/stream/BaseStream.java @@ -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: * *

{@code
  *     int sum = widgets.stream()
@@ -46,80 +47,18 @@ import java.util.function.Predicate;
  *                      .sum();
  * }
* - * In this example, {@code widgets} is a {@code Collection}. 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. - * - *

To perform a computation, stream - * operations are composed into a - * stream pipeline. A stream pipeline consists of a source (which - * might be an array, a collection, a generator function, an IO channel, - * etc), zero or more intermediate operations (which transform a - * stream into another stream, such as {@link Stream#filter(Predicate)}), and a - * terminal operation (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. - * - *

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. - * - *

A stream pipeline, like the "widgets" example above, can be viewed as - * a query 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. - * - *

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 functional interface 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 - * effectively stateless - * (their result should not depend on any state that might change during - * execution of the stream pipeline.) - * - *

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. - * - *

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.) - * - *

Stream pipelines may execute either sequentially or in - * parallel. 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 java.util.stream for additional + * specification of streams, stream operations, stream pipelines, and + * parallelism, which governs the behavior of all stream types. * * @param the type of the stream elements * @param the type of of the stream implementing {@code BaseStream} * @since 1.8 + * @see Stream + * @see IntStream + * @see LongStream + * @see DoubleStream * @see java.util.stream */ public interface BaseStream> diff --git a/src/share/classes/java/util/stream/Collectors.java b/src/share/classes/java/util/stream/Collectors.java index 00f7c866311c70a7714ec708b625c18226d464bc..93ffb0113c6cf866115da328d059d1d88d135a34 100644 --- a/src/share/classes/java/util/stream/Collectors.java +++ b/src/share/classes/java/util/stream/Collectors.java @@ -462,7 +462,7 @@ public final class Collectors { */ public static Collector summingInt(ToIntFunction mapper) { - return new CollectorImpl( + 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 Collector summingLong(ToLongFunction mapper) { - return new CollectorImpl( + 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 Collector summingDouble(ToDoubleFunction mapper) { - return new CollectorImpl( + 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 Collector averagingInt(ToIntFunction mapper) { - return new CollectorImpl( + 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 Collector averagingLong(ToLongFunction mapper) { - return new CollectorImpl( + 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 Collector averagingDouble(ToDoubleFunction mapper) { - return new CollectorImpl( + 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()); * } * + * @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 the type of the input elements * @param 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()))); * } * + * @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 the type of the input elements * @param the type of the keys * @param the intermediate accumulation type of the downstream collector @@ -798,6 +814,14 @@ public final class Collectors { * mapping(Person::getLastName, toSet()))); * } * + * @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 the type of the input elements * @param the type of the keys * @param the intermediate accumulation type of the downstream collector @@ -871,7 +895,7 @@ public final class Collectors { * @param the type of the input elements * @param 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 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()); * } * + * @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 the type of the input elements * @param the output type of the key mapping function * @param 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)); * } * + * @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 the type of the input elements * @param the output type of the key mapping function * @param 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 the type of the input elements * @param the output type of the key mapping function * @param 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 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 diff --git a/src/share/classes/java/util/stream/DoubleStream.java b/src/share/classes/java/util/stream/DoubleStream.java index b50471d02da63b4cc78592d7f763d9c42e4ed410..68d792d38ba0b58fa0909e5a2451f8e4861dd08e 100644 --- a/src/share/classes/java/util/stream/DoubleStream.java +++ b/src/share/classes/java/util/stream/DoubleStream.java @@ -50,9 +50,13 @@ import java.util.function.ObjDoubleConsumer; 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 DoubleStream}: + * A sequence of primitive double-valued elements supporting sequential and parallel + * aggregate operations. This is the {@code double} primitive specialization of + * {@link Stream}. + * + *

The following example illustrates an aggregate operation using + * {@link Stream} and {@link DoubleStream}, computing the sum of the weights of the + * red widgets: * *

{@code
  *     double sum = widgets.stream()
@@ -61,78 +65,13 @@ import java.util.function.Supplier;
  *                         .sum();
  * }
* - * In this example, {@code widgets} is a {@code Collection}. 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 double} values representing the weight of - * each red widget. Then this stream is summed to produce a total weight. - * - *

To perform a computation, stream - * operations are composed into a - * stream pipeline. A stream pipeline consists of a source (which - * might be an array, a collection, a generator function, an IO channel, - * etc), zero or more intermediate operations (which transform a - * stream into another stream, such as {@link DoubleStream#filter(DoublePredicate)}), and a - * terminal operation (which produces a result or side-effect, such - * as {@link DoubleStream#sum()} or {@link DoubleStream#forEach(DoubleConsumer)}. - * 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. - * - *

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. - * - *

A stream pipeline, like the "widgets" example above, can be viewed as - * a query 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. - * - *

Most stream operations accept parameters that describe user-specified - * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to - * {@code mapToDouble} in the example above. Such parameters are always instances - * of a functional interface 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 - * effectively stateless - * (their result should not depend on any state that might change during - * execution of the stream pipeline.) - * - *

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. - * - *

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.) - * - *

Stream pipelines may execute either sequentially or in - * parallel. 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 java.util.stream for additional + * specification of streams, stream operations, stream pipelines, and + * parallelism. * * @since 1.8 + * @see Stream * @see java.util.stream */ public interface DoubleStream extends BaseStream { @@ -144,9 +83,10 @@ public interface DoubleStream extends BaseStream { *

This is an intermediate * operation. * - * @param predicate a - * non-interfering, stateless predicate to apply to - * each element to determine if it should be included + * @param predicate a non-interfering, + * stateless + * predicate to apply to each element to determine if it + * should be included * @return the new stream */ DoubleStream filter(DoublePredicate predicate); @@ -158,9 +98,9 @@ public interface DoubleStream extends BaseStream { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to - * each element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ DoubleStream map(DoubleUnaryOperator mapper); @@ -173,9 +113,9 @@ public interface DoubleStream extends BaseStream { * intermediate operation. * * @param the element type of the new stream - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ Stream mapToObj(DoubleFunction mapper); @@ -187,9 +127,9 @@ public interface DoubleStream extends BaseStream { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ IntStream mapToInt(DoubleToIntFunction mapper); @@ -201,9 +141,9 @@ public interface DoubleStream extends BaseStream { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ LongStream mapToLong(DoubleToLongFunction mapper); @@ -218,10 +158,10 @@ public interface DoubleStream extends BaseStream { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to - * each element which produces an {@code DoubleStream} of new - * values + * @param mapper a non-interfering, + * stateless + * function to apply to each element which produces a + * {@code DoubleStream} of new values * @return the new stream * @see Stream#flatMap(Function) */ @@ -276,8 +216,8 @@ public interface DoubleStream extends BaseStream { * } * * @param action a - * non-interfering action to perform on the elements as - * they are consumed from the stream + * non-interfering action to perform on the elements as + * they are consumed from the stream * @return the new stream */ DoubleStream peek(DoubleConsumer action); @@ -423,9 +363,10 @@ public interface DoubleStream extends BaseStream { * synchronization and with greatly reduced risk of data races. * * @param identity the identity value for the accumulating function - * @param op an associative - * non-interfering, - * stateless function for combining two values + * @param op an associative, + * non-interfering, + * stateless + * function for combining two values * @return the result of the reduction * @see #sum() * @see #min() @@ -462,9 +403,10 @@ public interface DoubleStream extends BaseStream { *

This is a terminal * operation. * - * @param op an associative - * non-interfering, - * stateless function for combining two values + * @param op an associative, + * non-interfering, + * stateless + * function for combining two values * @return the result of the reduction * @see #reduce(double, DoubleBinaryOperator) */ @@ -495,14 +437,15 @@ public interface DoubleStream extends BaseStream { * @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 associative - * non-interfering, - * stateless function for incorporating an additional - * element into a result - * @param combiner an associative - * non-interfering, - * stateless function for combining two values, which - * must be compatible with the accumulator function + * @param accumulator an associative, + * non-interfering, + * stateless + * function for incorporating an additional element into a result + * @param combiner an associative, + * non-interfering, + * stateless + * 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) */ @@ -544,8 +487,8 @@ public interface DoubleStream extends BaseStream { *

This is a terminal * operation. * - * @apiNote Sorting values by increasing absolute magnitude tends to yield - * more accurate results. + * @apiNote Elements sorted by increasing absolute magnitude tend + * to yield more accurate results. * * @return the sum of elements in this stream */ @@ -651,48 +594,67 @@ public interface DoubleStream extends BaseStream { /** * 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. * *

This is a short-circuiting * terminal operation. * - * @param predicate a non-interfering, - * stateless predicate to apply to elements of this - * stream + * @apiNote + * This method evaluates the existential quantification of the + * predicate over the elements of the stream (for some x P(x)). + * + * @param predicate a non-interfering, + * stateless + * 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(DoublePredicate 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. * *

This is a short-circuiting * terminal operation. * - * @param predicate a non-interfering, - * stateless 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 universal quantification 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 vacuously + * satisfied and is always {@code true} (regardless of P(x)). + * + * @param predicate a non-interfering, + * stateless + * 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(DoublePredicate 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. * *

This is a short-circuiting * terminal operation. * - * @param predicate a non-interfering, - * stateless 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 universal quantification 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 non-interfering, + * stateless + * 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(DoublePredicate predicate); @@ -832,12 +794,12 @@ public interface DoubleStream extends BaseStream { } /** - * Returns a sequential stream where each element is generated by - * the provided {@code DoubleSupplier}. 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 DoubleSupplier}. This is suitable for + * generating constant streams, streams of random elements, etc. * * @param s the {@code DoubleSupplier} for generated elements - * @return a new sequential {@code DoubleStream} + * @return a new infinite sequential unordered {@code DoubleStream} */ public static DoubleStream generate(DoubleSupplier s) { Objects.requireNonNull(s); @@ -848,11 +810,16 @@ public interface DoubleStream extends BaseStream { /** * 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 diff --git a/src/share/classes/java/util/stream/IntStream.java b/src/share/classes/java/util/stream/IntStream.java index ae0eb4951d3d3697b4a9c6013a15a5fe05535298..b9fae57c7c70a1fd3c65c50ad3043a7a399fc968 100644 --- a/src/share/classes/java/util/stream/IntStream.java +++ b/src/share/classes/java/util/stream/IntStream.java @@ -24,11 +24,7 @@ */ package java.util.stream; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.Arrays; -import java.util.Collection; import java.util.IntSummaryStatistics; import java.util.Objects; import java.util.OptionalDouble; @@ -36,7 +32,6 @@ import java.util.OptionalInt; import java.util.PrimitiveIterator; import java.util.Spliterator; import java.util.Spliterators; -import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.IntBinaryOperator; @@ -51,9 +46,13 @@ import java.util.function.ObjIntConsumer; 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 IntStream}: + * A sequence of primitive int-valued elements supporting sequential and parallel + * aggregate operations. This is the {@code int} primitive specialization of + * {@link Stream}. + * + *

The following example illustrates an aggregate operation using + * {@link Stream} and {@link IntStream}, computing the sum of the weights of the + * red widgets: * *

{@code
  *     int sum = widgets.stream()
@@ -62,78 +61,13 @@ import java.util.function.Supplier;
  *                      .sum();
  * }
* - * In this example, {@code widgets} is a {@code Collection}. 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. - * - *

To perform a computation, stream - * operations are composed into a - * stream pipeline. A stream pipeline consists of a source (which - * might be an array, a collection, a generator function, an IO channel, - * etc), zero or more intermediate operations (which transform a - * stream into another stream, such as {@link IntStream#filter(IntPredicate)}), and a - * terminal operation (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. - * - *

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. - * - *

A stream pipeline, like the "widgets" example above, can be viewed as - * a query 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. - * - *

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 functional interface 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 - * effectively stateless - * (their result should not depend on any state that might change during - * execution of the stream pipeline.) - * - *

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. - * - *

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.) - * - *

Stream pipelines may execute either sequentially or in - * parallel. 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 java.util.stream for additional + * specification of streams, stream operations, stream pipelines, and + * parallelism. * * @since 1.8 + * @see Stream * @see java.util.stream */ public interface IntStream extends BaseStream { @@ -145,9 +79,10 @@ public interface IntStream extends BaseStream { *

This is an intermediate * operation. * - * @param predicate a - * non-interfering, stateless predicate to apply to - * each element to determine if it should be included + * @param predicate a non-interfering, + * stateless + * predicate to apply to each element to determine if it + * should be included * @return the new stream */ IntStream filter(IntPredicate predicate); @@ -159,9 +94,9 @@ public interface IntStream extends BaseStream { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ IntStream map(IntUnaryOperator mapper); @@ -174,9 +109,9 @@ public interface IntStream extends BaseStream { * intermediate operation. * * @param the element type of the new stream - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ Stream mapToObj(IntFunction mapper); @@ -188,9 +123,9 @@ public interface IntStream extends BaseStream { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ LongStream mapToLong(IntToLongFunction mapper); @@ -202,9 +137,9 @@ public interface IntStream extends BaseStream { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ DoubleStream mapToDouble(IntToDoubleFunction mapper); @@ -219,10 +154,10 @@ public interface IntStream extends BaseStream { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to - * each element which produces an {@code IntStream} of new - * values + * @param mapper a non-interfering, + * stateless + * function to apply to each element which produces an + * {@code IntStream} of new values * @return the new stream * @see Stream#flatMap(Function) */ @@ -421,9 +356,10 @@ public interface IntStream extends BaseStream { * synchronization and with greatly reduced risk of data races. * * @param identity the identity value for the accumulating function - * @param op an associative - * non-interfering, - * stateless function for combining two values + * @param op an associative, + * non-interfering, + * stateless + * function for combining two values * @return the result of the reduction * @see #sum() * @see #min() @@ -460,9 +396,10 @@ public interface IntStream extends BaseStream { *

This is a terminal * operation. * - * @param op an associative - * non-interfering, - * stateless function for combining two values + * @param op an associative, + * non-interfering, + * stateless + * function for combining two values * @return the result of the reduction * @see #reduce(int, IntBinaryOperator) */ @@ -492,14 +429,15 @@ public interface IntStream extends BaseStream { * @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 associative - * non-interfering, - * stateless function for incorporating an additional - * element into a result - * @param combiner an associative - * non-interfering, - * stateless function for combining two values, which - * must be compatible with the accumulator function + * @param accumulator an associative, + * non-interfering, + * stateless + * function for incorporating an additional element into a result + * @param combiner an associative, + * non-interfering, + * stateless + * 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 +537,67 @@ public interface IntStream extends BaseStream { /** * 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. * *

This is a short-circuiting * terminal operation. * - * @param predicate a non-interfering, - * stateless predicate to apply to elements of this - * stream + * @apiNote + * This method evaluates the existential quantification of the + * predicate over the elements of the stream (for some x P(x)). + * + * @param predicate a non-interfering, + * stateless + * 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(IntPredicate 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. * *

This is a short-circuiting * terminal operation. * - * @param predicate a non-interfering, - * stateless 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 universal quantification 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 vacuously + * satisfied and is always {@code true} (regardless of P(x)). + * + * @param predicate a non-interfering, + * stateless + * 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(IntPredicate 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. * *

This is a short-circuiting * terminal operation. * - * @param predicate a non-interfering, - * stateless 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 universal quantification 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 non-interfering, + * stateless + * 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(IntPredicate predicate); @@ -803,12 +760,12 @@ public interface IntStream extends BaseStream { } /** - * Returns a sequential stream where each element is generated by - * the provided {@code IntSupplier}. 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 IntSupplier}. This is suitable for + * generating constant streams, streams of random elements, etc. * * @param s the {@code IntSupplier} for generated elements - * @return a new sequential {@code IntStream} + * @return a new infinite sequential unordered {@code IntStream} */ public static IntStream generate(IntSupplier s) { Objects.requireNonNull(s); @@ -871,11 +828,16 @@ public interface IntStream extends BaseStream { /** * 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 diff --git a/src/share/classes/java/util/stream/LongStream.java b/src/share/classes/java/util/stream/LongStream.java index 0b8fb157fb17a87e480269effe4df3478926b6f6..d9fe6b391a552db4c666e4397c4aa3ff3d9e28fc 100644 --- a/src/share/classes/java/util/stream/LongStream.java +++ b/src/share/classes/java/util/stream/LongStream.java @@ -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}. + * + *

The following example illustrates an aggregate operation using + * {@link Stream} and {@link LongStream}, computing the sum of the weights of the + * red widgets: * *

{@code
  *     long sum = widgets.stream()
@@ -62,78 +66,13 @@ import java.util.function.Supplier;
  *                       .sum();
  * }
* - * In this example, {@code widgets} is a {@code Collection}. 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. - * - *

To perform a computation, stream - * operations are composed into a - * stream pipeline. A stream pipeline consists of a source (which - * might be an array, a collection, a generator function, an IO channel, - * etc), zero or more intermediate operations (which transform a - * stream into another stream, such as {@link LongStream#filter(LongPredicate)}), and a - * terminal operation (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. - * - *

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. - * - *

A stream pipeline, like the "widgets" example above, can be viewed as - * a query 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. - * - *

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 functional interface 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 - * effectively stateless - * (their result should not depend on any state that might change during - * execution of the stream pipeline.) - * - *

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. - * - *

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.) - * - *

Stream pipelines may execute either sequentially or in - * parallel. 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 java.util.stream for additional + * specification of streams, stream operations, stream pipelines, and + * parallelism. * * @since 1.8 + * @see Stream * @see java.util.stream */ public interface LongStream extends BaseStream { @@ -145,9 +84,10 @@ public interface LongStream extends BaseStream { *

This is an intermediate * operation. * - * @param predicate a - * non-interfering, stateless predicate to apply to - * each element to determine if it should be included + * @param predicate a non-interfering, + * stateless + * 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 { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ LongStream map(LongUnaryOperator mapper); @@ -174,9 +114,9 @@ public interface LongStream extends BaseStream { * intermediate operation. * * @param the element type of the new stream - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ Stream mapToObj(LongFunction mapper); @@ -188,9 +128,9 @@ public interface LongStream extends BaseStream { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ IntStream mapToInt(LongToIntFunction mapper); @@ -202,9 +142,9 @@ public interface LongStream extends BaseStream { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ DoubleStream mapToDouble(LongToDoubleFunction mapper); @@ -219,10 +159,10 @@ public interface LongStream extends BaseStream { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to - * each element which produces an {@code LongStream} of new - * values + * @param mapper a non-interfering, + * stateless + * 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 { * synchronization and with greatly reduced risk of data races. * * @param identity the identity value for the accumulating function - * @param op an associative - * non-interfering, - * stateless function for combining two values + * @param op an associative, + * non-interfering, + * stateless + * function for combining two values * @return the result of the reduction * @see #sum() * @see #min() @@ -460,9 +401,10 @@ public interface LongStream extends BaseStream { *

This is a terminal * operation. * - * @param op an associative - * non-interfering, - * stateless function for combining two values + * @param op an associative, + * non-interfering, + * stateless + * function for combining two values * @return the result of the reduction * @see #reduce(long, LongBinaryOperator) */ @@ -492,14 +434,15 @@ public interface LongStream extends BaseStream { * @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 associative - * non-interfering, - * stateless function for incorporating an additional - * element into a result - * @param combiner an associative - * non-interfering, - * stateless function for combining two values, which - * must be compatible with the accumulator function + * @param accumulator an associative, + * non-interfering, + * stateless + * function for incorporating an additional element into a result + * @param combiner an associative, + * non-interfering, + * stateless + * 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 { /** * 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. * *

This is a short-circuiting * terminal operation. * - * @param predicate a non-interfering, - * stateless predicate to apply to elements of this - * stream + * @apiNote + * This method evaluates the existential quantification of the + * predicate over the elements of the stream (for some x P(x)). + * + * @param predicate a non-interfering, + * stateless + * 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. * *

This is a short-circuiting * terminal operation. * - * @param predicate a non-interfering, - * stateless 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 universal quantification 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 vacuously + * satisfied and is always {@code true} (regardless of P(x)). + * + * @param predicate a non-interfering, + * stateless + * 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. * *

This is a short-circuiting * terminal operation. * - * @param predicate a non-interfering, - * stateless 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 universal quantification 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 non-interfering, + * stateless + * 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 { } /** - * 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 { /** * 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 diff --git a/src/share/classes/java/util/stream/Node.java b/src/share/classes/java/util/stream/Node.java index 381d06defbee3dd992a79776219deff4f5beac75..2b4360bea572ffec72efe4f5c88a5567b180213f 100644 --- a/src/share/classes/java/util/stream/Node.java +++ b/src/share/classes/java/util/stream/Node.java @@ -241,6 +241,7 @@ interface Node { * @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 diff --git a/src/share/classes/java/util/stream/SpinedBuffer.java b/src/share/classes/java/util/stream/SpinedBuffer.java index e7fac67510f8dc346b44bb8cb539ed30bb7e17f8..878b2c2899ed9831ea06f5156852cdd11c7a7f3b 100644 --- a/src/share/classes/java/util/stream/SpinedBuffer.java +++ b/src/share/classes/java/util/stream/SpinedBuffer.java @@ -579,6 +579,7 @@ class SpinedBuffer spineIndex = 0; } + @SuppressWarnings("overloads") public void forEach(T_CONS consumer) { // completed chunks, if any for (int j = 0; j < spineIndex; j++) diff --git a/src/share/classes/java/util/stream/Stream.java b/src/share/classes/java/util/stream/Stream.java index 1961359d9b50f6e309f9d44dec05586425043c89..9c88e6887bb14d188422ef15ce4308afbe5d1996 100644 --- a/src/share/classes/java/util/stream/Stream.java +++ b/src/share/classes/java/util/stream/Stream.java @@ -67,6 +67,11 @@ import java.util.function.UnaryOperator; * 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. * + *

In addition to {@code Stream}, which is a stream of object references, + * there are primitive specializations for {@link IntStream}, {@link LongStream}, + * and {@link DoubleStream}, all of which are referred to as "streams" and + * conform to the characteristics and restrictions described here. + * *

To perform a computation, stream * operations are composed into a * stream pipeline. A stream pipeline consists of a source (which @@ -97,14 +102,21 @@ import java.util.function.UnaryOperator; * *

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 functional interface such + * {@code mapToInt} in the example above. To preserve correct behavior, + * these behavioral parameters: + *

    + *
  • must be non-interfering + * (they do not modify the stream source); and
  • + *
  • in most cases must be stateless + * (their result should not depend on any state that might change during execution + * of the stream pipeline).
  • + *
+ * + *

Such parameters are always instances of a + * functional interface 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 - * effectively stateless - * (their result should not depend on any state that might change during - * execution of the stream pipeline.) + * method references. Unless otherwise specified these parameters must be + * non-null. * *

A stream should be operated on (invoking an intermediate or terminal stream * operation) only once. This rules out, for example, "forked" streams, where @@ -134,6 +146,9 @@ import java.util.function.UnaryOperator; * * @param the type of the stream elements * @since 1.8 + * @see IntStream + * @see LongStream + * @see DoubleStream * @see java.util.stream */ public interface Stream extends BaseStream> { @@ -145,9 +160,10 @@ public interface Stream extends BaseStream> { *

This is an intermediate * operation. * - * @param predicate a - * non-interfering, stateless predicate to apply to - * each element to determine if it should be included + * @param predicate a non-interfering, + * stateless + * predicate to apply to each element to determine if it + * should be included * @return the new stream */ Stream filter(Predicate predicate); @@ -160,9 +176,9 @@ public interface Stream extends BaseStream> { * operation. * * @param The element type of the new stream - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ Stream map(Function mapper); @@ -174,9 +190,9 @@ public interface Stream extends BaseStream> { *

This is an * intermediate operation. * - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ IntStream mapToInt(ToIntFunction mapper); @@ -188,9 +204,9 @@ public interface Stream extends BaseStream> { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ LongStream mapToLong(ToLongFunction mapper); @@ -202,9 +218,9 @@ public interface Stream extends BaseStream> { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to each - * element + * @param mapper a non-interfering, + * stateless + * function to apply to each element * @return the new stream */ DoubleStream mapToDouble(ToDoubleFunction mapper); @@ -221,19 +237,33 @@ public interface Stream extends BaseStream> { * * @apiNote * The {@code flatMap()} operation has the effect of applying a one-to-many - * tranformation to the elements of the stream, and then flattening the - * resulting elements into a new stream. For example, if {@code orders} - * is a stream of purchase orders, and each purchase order contains a - * collection of line items, then the following produces a stream of line - * items: + * transformation to the elements of the stream, and then flattening the + * resulting elements into a new stream. + * + *

Examples. + * + *

If {@code orders} is a stream of purchase orders, and each purchase + * order contains a collection of line items, then the following produces a + * stream containing all the line items in all the orders: + *

{@code
+     *     orders.flatMap(order -> order.getLineItems().stream())...
+     * }
+ * + *

If {@code path} is the path to a file, then the following produces a + * stream of the {@code words} contained in that file: *

{@code
-     *     orderStream.flatMap(order -> order.getLineItems().stream())...
+     *     Stream lines = Files.lines(path, StandardCharsets.UTF_8);
+     *     Stream words = lines.flatMap(line -> Stream.of(line.split(" +")));
      * }
+ * The {@code mapper} function passed to {@code flatMap} splits a line, + * using a simple regular expression, into an array of words, and then + * creates a stream of words from that array. * * @param The element type of the new stream - * @param mapper a - * non-interfering, stateless function to apply to each - * element which produces a stream of new values + * @param mapper a non-interfering, + * stateless + * function to apply to each element which produces a stream + * of new values * @return the new stream */ Stream flatMap(Function> mapper); @@ -248,10 +278,12 @@ public interface Stream extends BaseStream> { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to each - * element which produces a stream of new values + * @param mapper a non-interfering, + * stateless + * function to apply to each element which produces a stream + * of new values * @return the new stream + * @see #flatMap(Function) */ IntStream flatMapToInt(Function mapper); @@ -265,10 +297,12 @@ public interface Stream extends BaseStream> { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to - * each element which produces a stream of new values + * @param mapper a non-interfering, + * stateless + * function to apply to each element which produces a stream + * of new values * @return the new stream + * @see #flatMap(Function) */ LongStream flatMapToLong(Function mapper); @@ -282,10 +316,12 @@ public interface Stream extends BaseStream> { *

This is an intermediate * operation. * - * @param mapper a - * non-interfering, stateless function to apply to each - * element which produces a stream of new values + * @param mapper a non-interfering, + * stateless + * function to apply to each element which produces a stream + * of new values * @return the new stream + * @see #flatMap(Function) */ DoubleStream flatMapToDouble(Function mapper); @@ -293,9 +329,27 @@ public interface Stream extends BaseStream> { * Returns a stream consisting of the distinct elements (according to * {@link Object#equals(Object)}) of this stream. * + *

For ordered streams, the selection of distinct elements is stable + * (for duplicated elements, the element appearing first in the encounter + * order is preserved.) For unordered streams, no stability guarantees + * are made. + * *

This is a stateful * intermediate operation. * + * @apiNote + * Preserving stability for {@code distinct()} in parallel pipelines is + * relatively expensive (requires that the operation act as a full barrier, + * with substantial buffering overhead), and stability is often not needed. + * Using an unordered stream source (such as {@link #generate(Supplier)}) + * or removing the ordering constraint with {@link #unordered()} may result + * in significantly more efficient execution for {@code distinct()} in parallel + * pipelines, if the semantics of your situation permit. If consistency + * with encounter order is required, and you are experiencing poor performance + * or memory utilization with {@code distinct()} in parallel pipelines, + * switching to sequential execution with {@link #sequential()} may improve + * performance. + * * @return the new stream */ Stream distinct(); @@ -306,6 +360,9 @@ public interface Stream extends BaseStream> { * {@code Comparable}, a {@code java.lang.ClassCastException} may be thrown * when the terminal operation is executed. * + *

For ordered streams, the sort is stable. For unordered streams, no + * stability guarantees are made. + * *

This is a stateful * intermediate operation. * @@ -317,12 +374,15 @@ public interface Stream extends BaseStream> { * Returns a stream consisting of the elements of this stream, sorted * according to the provided {@code Comparator}. * + *

For ordered streams, the sort is stable. For unordered streams, no + * stability guarantees are made. + * *

This is a stateful * intermediate operation. * - * @param comparator a - * non-interfering, stateless {@code Comparator} to - * be used to compare stream elements + * @param comparator a non-interfering, + * stateless + * {@code Comparator} to be used to compare stream elements * @return the new stream */ Stream sorted(Comparator comparator); @@ -420,7 +480,8 @@ public interface Stream extends BaseStream> { *

This is a terminal * operation. * - *

For parallel stream pipelines, this operation does not + *

The behavior of this operation is explicitly nondeterministic. + * For parallel stream pipelines, this operation does not * guarantee to respect the encounter order of the stream, as doing so * would sacrifice the benefit of parallelism. For any given element, the * action may be performed at whatever time and in whatever thread the @@ -433,13 +494,18 @@ public interface Stream extends BaseStream> { void forEach(Consumer action); /** - * Performs an action for each element of this stream, guaranteeing that - * each element is processed in encounter order for streams that have a - * defined encounter order. + * Performs an action for each element of this stream, in the encounter + * order of the stream if the stream has a defined encounter order. * *

This is a terminal * operation. * + *

This operation processes the elements one at a time, in encounter + * order if one exists. Performing the action for one element + * happens-before + * performing the action for subsequent elements, but for any given element, + * the action may be performed in whatever thread the library chooses. + * * @param action a * non-interfering action to perform on the elements * @see #forEach(Consumer) @@ -528,9 +594,10 @@ public interface Stream extends BaseStream> { * synchronization and with greatly reduced risk of data races. * * @param identity the identity value for the accumulating function - * @param accumulator an associative - * non-interfering, - * stateless function for combining two values + * @param accumulator an associative, + * non-interfering, + * stateless + * function for combining two values * @return the result of the reduction */ T reduce(T identity, BinaryOperator accumulator); @@ -563,14 +630,15 @@ public interface Stream extends BaseStream> { *

This is a terminal * operation. * - * @param accumulator an associative - * non-interfering, - * stateless function for combining two values + * @param accumulator an associative, + * non-interfering, + * stateless + * function for combining two values * @return an {@link Optional} describing the result of the reduction * @throws NullPointerException if the result of the reduction is null * @see #reduce(Object, BinaryOperator) - * @see #min(java.util.Comparator) - * @see #max(java.util.Comparator) + * @see #min(Comparator) + * @see #max(Comparator) */ Optional reduce(BinaryOperator accumulator); @@ -608,14 +676,15 @@ public interface Stream extends BaseStream> { * * @param The type of the result * @param identity the identity value for the combiner function - * @param accumulator an associative - * non-interfering, - * stateless function for incorporating an additional - * element into a result - * @param combiner an associative - * non-interfering, - * stateless function for combining two values, which - * must be compatible with the accumulator function + * @param accumulator an associative, + * non-interfering, + * stateless + * function for incorporating an additional element into a result + * @param combiner an associative, + * non-interfering, + * stateless + * function for combining two values, which must be + * compatible with the accumulator function * @return the result of the reduction * @see #reduce(BinaryOperator) * @see #reduce(Object, BinaryOperator) @@ -664,14 +733,15 @@ public interface Stream extends BaseStream> { * @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 associative - * non-interfering, - * stateless function for incorporating an additional - * element into a result - * @param combiner an associative - * non-interfering, - * stateless function for combining two values, which - * must be compatible with the accumulator function + * @param accumulator an associative, + * non-interfering, + * stateless + * function for incorporating an additional element into a result + * @param combiner an associative, + * non-interfering, + * stateless + * function for combining two values, which must be + * compatible with the accumulator function * @return the result of the reduction */ R collect(Supplier supplier, @@ -687,6 +757,13 @@ public interface Stream extends BaseStream> { * collection strategies and composition of collect operations such as * multiple-level grouping or partitioning. * + *

If the stream is parallel, and the {@code Collector} + * is {@link Collector.Characteristics#CONCURRENT concurrent}, and + * either the stream is unordered or the collector is + * {@link Collector.Characteristics#UNORDERED unordered}, + * then a concurrent reduction will be performed (see {@link Collector} for + * details on concurrent reduction.) + * *

This is a terminal * operation. * @@ -732,9 +809,9 @@ public interface Stream extends BaseStream> { * *

This is a terminal operation. * - * @param comparator a non-interfering, - * stateless {@code Comparator} to use to compare - * elements of this stream + * @param comparator a non-interfering, + * stateless + * {@code Comparator} to compare elements of this stream * @return an {@code Optional} describing the minimum element of this stream, * or an empty {@code Optional} if the stream is empty * @throws NullPointerException if the minimum element is null @@ -749,9 +826,9 @@ public interface Stream extends BaseStream> { *

This is a terminal * operation. * - * @param comparator a non-interfering, - * stateless {@code Comparator} to use to compare - * elements of this stream + * @param comparator a non-interfering, + * stateless + * {@code Comparator} to compare elements of this stream * @return an {@code Optional} describing the maximum element of this stream, * or an empty {@code Optional} if the stream is empty * @throws NullPointerException if the maximum element is null @@ -775,48 +852,67 @@ public interface Stream extends BaseStream> { /** * 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. * *

This is a short-circuiting * terminal operation. * - * @param predicate a non-interfering, - * stateless predicate to apply to elements of this - * stream + * @apiNote + * This method evaluates the existential quantification of the + * predicate over the elements of the stream (for some x P(x)). + * + * @param predicate a non-interfering, + * stateless + * 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(Predicate 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. * *

This is a short-circuiting * terminal operation. * - * @param predicate a non-interfering, - * stateless 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 universal quantification 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 vacuously + * satisfied and is always {@code true} (regardless of P(x)). + * + * @param predicate a non-interfering, + * stateless + * 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(Predicate 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. * *

This is a short-circuiting * terminal operation. * - * @param predicate a non-interfering, - * stateless 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 universal quantification 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 non-interfering, + * stateless + * 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(Predicate predicate); @@ -939,13 +1035,13 @@ public interface Stream extends BaseStream> { } /** - * Returns a sequential stream where each element is generated by - * the provided {@code Supplier}. 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 Supplier}. This is suitable for + * generating constant streams, streams of random elements, etc. * * @param the type of stream elements * @param s the {@code Supplier} of generated elements - * @return a new sequential {@code Stream} + * @return a new infinite sequential unordered {@code Stream} */ public static Stream generate(Supplier s) { Objects.requireNonNull(s); @@ -956,11 +1052,16 @@ public interface Stream extends BaseStream> { /** * 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 The type of stream elements * @param a the first stream * @param b the second stream diff --git a/src/share/classes/java/util/stream/StreamSupport.java b/src/share/classes/java/util/stream/StreamSupport.java index 6feadd1db216f3459f3ef7da02d98035f0d09a95..70af2da5e3b18b64af94cbbb10265cee7abb5abf 100644 --- a/src/share/classes/java/util/stream/StreamSupport.java +++ b/src/share/classes/java/util/stream/StreamSupport.java @@ -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. diff --git a/src/share/classes/java/util/stream/package-info.java b/src/share/classes/java/util/stream/package-info.java index 440054eb46858d9b5e680d652b40fee3d2c238ad..810e2fc37f9dad37c3ca65a9a0129c5b91affd33 100644 --- a/src/share/classes/java/util/stream/package-info.java +++ b/src/share/classes/java/util/stream/package-info.java @@ -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